1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2002 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.org
8 
9   This program is free software which we release under the GNU General Public
10   License. You may redistribute and/or modify this program under the terms
11   of that license as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   To get a copy of the GNU General Public License, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 */
23 
24 #include "config.h"
25 #include "fwbuilder/libfwbuilder-config.h"
26 
27 #include <assert.h>
28 
29 #include "Compiler.h"
30 
31 #include "fwbuilder/AddressRange.h"
32 #include "fwbuilder/Cluster.h"
33 #include "fwbuilder/CustomService.h"
34 #include "fwbuilder/DNSName.h"
35 #include "fwbuilder/FWException.h"
36 #include "fwbuilder/FWObjectDatabase.h"
37 #include "fwbuilder/FWObjectReference.h"
38 #include "fwbuilder/FWServiceReference.h"
39 #include "fwbuilder/FailoverClusterGroup.h"
40 #include "fwbuilder/Firewall.h"
41 #include "fwbuilder/Group.h"
42 #include "fwbuilder/ICMP6Service.h"
43 #include "fwbuilder/ICMPService.h"
44 #include "fwbuilder/IPService.h"
45 #include "fwbuilder/IPv4.h"
46 #include "fwbuilder/IPv6.h"
47 #include "fwbuilder/Interface.h"
48 #include "fwbuilder/Library.h"
49 #include "fwbuilder/MultiAddress.h"
50 #include "fwbuilder/Network.h"
51 #include "fwbuilder/NetworkIPv6.h"
52 #include "fwbuilder/Policy.h"
53 #include "fwbuilder/Rule.h"
54 #include "fwbuilder/RuleElement.h"
55 #include "fwbuilder/RuleSet.h"
56 #include "fwbuilder/TCPService.h"
57 #include "fwbuilder/UDPService.h"
58 #include "fwbuilder/XMLTools.h"
59 
60 #include <iostream>
61 #include <iomanip>
62 #include <algorithm>
63 #include <functional>
64 #include <fstream>
65 #include <string>
66 
67 
68 using namespace libfwbuilder;
69 using namespace fwcompiler;
70 using namespace std;
71 
72 
prolog()73 int Compiler::prolog()
74 {
75     temp = new Group();
76     temp->setName("Temp Group");
77     fw->add(temp, false);
78     return 0;
79 }
80 
epilog()81 void Compiler::epilog()
82 {
83 }
84 
abort(const string & errstr)85 void Compiler::abort(const string &errstr) throw(FWException)
86 {
87     BaseCompiler::abort(fw, source_ruleset, NULL, errstr);
88 }
89 
abort(FWObject * rule,const string & errstr)90 void Compiler::abort(FWObject *rule, const string &errstr) throw(FWException)
91 {
92     BaseCompiler::abort(fw, source_ruleset, rule, errstr);
93 }
94 
error(const string & errstr)95 void Compiler::error(const string &errstr)
96 {
97     BaseCompiler::error(fw, source_ruleset, NULL, errstr);
98 }
99 
error(FWObject * rule,const string & errstr)100 void Compiler::error(FWObject *rule, const string &errstr)
101 {
102     BaseCompiler::error(fw, source_ruleset, rule, errstr);
103 }
104 
warning(const string & errstr)105 void Compiler::warning(const string &errstr)
106 {
107     BaseCompiler::warning(fw, source_ruleset, NULL, errstr);
108 }
109 
warning(FWObject * rule,const string & errstr)110 void Compiler::warning(FWObject *rule, const string &errstr)
111 {
112     BaseCompiler::warning(fw, source_ruleset, rule, errstr);
113 }
114 
getCompiledScriptLength()115 int Compiler::getCompiledScriptLength()
116 {
117     return int(output.tellp());
118 }
119 
getCompiledScript()120 string Compiler::getCompiledScript()
121 {
122     string res;
123     res=output.str();
124 
125 /*
126  * NB: according to Rogue Wave docs, method  basic_stringbuf::seekpos is public,
127  * however implementation that comes with g++ 3.x declares it as protected
128  *
129  * Method str(const char*) is not described in Rogue Wave docs at
130  * all. Stroustrup does not methion it either.
131  */
132 //    output.rdbuf()->seekpos(0);
133     output.str("");
134     return res;
135 }
136 
_init(FWObjectDatabase * _db,Firewall * _fw)137 void Compiler::_init(FWObjectDatabase *_db, Firewall *_fw)
138 {
139     initialized = false;
140     _cntr_ = 1;
141     group_registry = NULL;
142 
143     temp_ruleset = NULL;
144 
145     debug = 0;
146     debug_rule = -1;
147     rule_debug_on = false;
148     verbose = true;
149     single_rule_mode = false;
150     single_rule_ruleset_name = "";
151     single_rule_position = -1;
152 
153     dbcopy = NULL;
154     persistent_objects = NULL;
155     fw = NULL;
156     fwopt = NULL;
157     fw_id = -1;
158 
159     if (_db != NULL && _fw != NULL)
160     {
161         assert(_fw->getRoot() == _db);
162 
163         dbcopy = _db;
164         fw = _fw;
165         fwopt = fw->getOptionsObject();
166         fw_id = fw->getId();
167 
168         // string fw_str_id = FWObjectDatabase::getStringId(_fw->getId());
169         // dbcopy = new FWObjectDatabase(*_db);  // copies entire tree
170         // fw = Firewall::cast(
171         //     dbcopy->findInIndex(FWObjectDatabase::getIntId(fw_str_id)));
172         // fwopt = fw->getOptionsObject();
173         // fw_id = fw->getId();
174     }
175 }
176 
Compiler(FWObjectDatabase * _db,Firewall * fw,bool ipv6_policy)177 Compiler::Compiler(FWObjectDatabase *_db, Firewall *fw, bool ipv6_policy)
178 {
179     source_ruleset = NULL;
180     ruleSetName = "";
181     osconfigurator = NULL;
182     countIPv6Rules = 0;
183     ipv6 = ipv6_policy;
184     persistent_objects = NULL;
185     _init(_db, fw);
186 }
187 
Compiler(FWObjectDatabase * _db,Firewall * fw,bool ipv6_policy,OSConfigurator * _oscnf)188 Compiler::Compiler(FWObjectDatabase *_db, Firewall *fw, bool ipv6_policy,
189 		   OSConfigurator *_oscnf)
190 {
191     source_ruleset = NULL;
192     ruleSetName = "";
193     osconfigurator = _oscnf;
194     countIPv6Rules = 0;
195     ipv6 = ipv6_policy;
196     persistent_objects = NULL;
197     _init(_db, fw);
198 }
199 
200 // this constructor is used by class Preprocessor, it does not call _init
Compiler(FWObjectDatabase *,bool ipv6_policy)201 Compiler::Compiler(FWObjectDatabase*, bool ipv6_policy)
202 {
203     source_ruleset = NULL;
204     ruleSetName = "";
205     osconfigurator = NULL;
206     countIPv6Rules = 0;
207     ipv6 = ipv6_policy;
208     initialized = false;
209     _cntr_ = 1;
210     persistent_objects = NULL;
211     fw = NULL;
212     temp_ruleset = NULL;
213     debug = 0;
214     debug_rule = -1;
215     rule_debug_on = false;
216     verbose = true;
217     single_rule_mode = false;
218 }
219 
~Compiler()220 Compiler::~Compiler()
221 {
222     deleteRuleProcessors();
223     dbcopy = NULL;
224 }
225 
setPersistentObjects(Library * po)226 void Compiler::setPersistentObjects(Library* po)
227 {
228     persistent_objects = po;
229     dbcopy->reparent(persistent_objects);
230     persistent_objects->fixTree();
231 }
232 
setSourceRuleSet(RuleSet * rs)233 void Compiler::setSourceRuleSet(RuleSet *rs)
234 {
235     FWObject *copy_rs = dbcopy->findInIndex(rs->getId());
236     source_ruleset = RuleSet::cast(copy_rs);
237 }
238 
setSingleRuleCompileMode(const string & rule_id)239 void Compiler::setSingleRuleCompileMode(const string &rule_id)
240 {
241     if (!rule_id.empty())
242     {
243         Rule *rule = Rule::cast(
244             dbcopy->findInIndex(FWObjectDatabase::getIntId(rule_id)));
245         if (rule)
246         {
247             single_rule_mode = true;
248             single_rule_compile_rule = rule;
249             single_rule_position = rule->getPosition();
250             single_rule_ruleset_name = rule->getParent()->getName();
251         }
252     }
253 }
254 
createRuleLabel(const std::string & prefix,const string & txt,int rule_num)255 string Compiler::createRuleLabel(const std::string &prefix,
256                                  const string &txt, int rule_num)
257 {
258     ostringstream  str;
259 
260     if (!prefix.empty()) str << prefix << " ";
261     str << rule_num << " ";
262     str << "(" << txt << ")";
263     return str.str();
264 }
265 
getUniqueRuleLabel()266 string Compiler::getUniqueRuleLabel()
267 {
268     ostringstream str;
269     str << "R_" << _cntr_;
270     _cntr_++;
271     return str.str();
272 }
273 
compile()274 void Compiler::compile()
275 {
276     assert(fw);
277 }
278 
_expand_group_recursive(FWObject * o,list<FWObject * > & ol)279 void Compiler::_expand_group_recursive(FWObject *o, list<FWObject*> &ol)
280 {
281 /*
282  * ref #50: ignore various Options child objects. In particular this
283  * skips ClusterGroupOptions object which is a child of
284  * FailoverClusterGroup and StateSyncClusterGroup objects.
285  */
286     if (FWOptions::cast(o)) return;
287 
288 /* special case: MultiAddress. This class inherits ObjectGroup, but
289  * should not be expanded if it is expanded at run time
290  *
291  * This is now redundant since we use class MultiAddressRunTime for
292  * run-time address tables
293  */
294     MultiAddress *adt = MultiAddress::cast(o);
295 
296     if ((Group::cast(o)!=NULL && adt==NULL) ||
297         (adt!=NULL && adt->isCompileTime()))
298     {
299 	for (FWObject::iterator i2=o->begin(); i2!=o->end(); ++i2)
300         {
301             FWObject *o1 = FWReference::getObject(*i2);
302 	    assert(o1);
303 
304 	    _expand_group_recursive(o1, ol);
305 	}
306     } else
307     {
308         if (o->getId() == FWObjectDatabase::ANY_ADDRESS_ID)
309         {
310             o->ref();
311             ol.push_back( o );
312         } else
313         {
314             Address *oaddr = Address::cast(o);
315             if (oaddr && oaddr->hasInetAddress())
316             {
317                 if (MatchesAddressFamily(o))
318                 {
319                     o->ref();
320                     ol.push_back( o );
321                 }
322             } else
323             {
324                 // not an address object at all
325                 o->ref();
326                 ol.push_back( o );
327             }
328         }
329     }
330 }
331 
332 /*
333  * Common interface to the operation of expanding of a group
334  * recursively. This just calls internal function
335  * _expand_group_recursive()
336  */
expandGroup(FWObject * grp,list<FWObject * > & ol)337 void Compiler::expandGroup(FWObject *grp, list<FWObject*> &ol)
338 {
339     for (FWObject::iterator i1=grp->begin(); i1!=grp->end(); ++i1)
340     {
341         FWObject *o = FWReference::getObject(*i1);
342         assert(o);
343         _expand_group_recursive(o, ol);
344     }
345 }
346 
347 /**
348  *   object 's' here is really src or dst or srv. Its children objects
349  *   should all be references
350  */
expandGroupsInRuleElement(RuleElement * s)351 void Compiler::expandGroupsInRuleElement(RuleElement *s)
352 {
353     list<FWObject*> cl;
354     expandGroup(s, cl);
355 
356     s->clearChildren();
357     //s->setAnyElement();
358 
359     cl.sort(FWObjectNameCmpPredicate());
360 
361     for(FWObject::iterator i2=cl.begin(); i2!=cl.end(); ++i2)
362     {
363         if (!s->validateChild(*i2))
364             abort(s->getParent(),
365                   "Object '" + (*i2)->getName() +
366                   "' can not be used in rule element " + s->getTypeName());
367 
368         s->addRef( *i2 );
369     }
370 }
371 
_expand_addr_recursive(Rule * rule,FWObject * s,list<FWObject * > & ol,bool expand_cluster_interfaces_fully)372 void Compiler::_expand_addr_recursive(Rule *rule, FWObject *s,
373                                       list<FWObject*> &ol,
374                                       bool expand_cluster_interfaces_fully)
375 {
376 //    Interface *rule_iface = Interface::cast(dbcopy->findInIndex(rule->getInterfaceId()));
377     bool on_loopback = false;
378 
379     if (PolicyRule::isA(rule))
380     {
381         RuleElement *intf_re = PolicyRule::cast(rule)->getItf();
382         Interface *rule_iface =
383             Interface::cast(FWObjectReference::getObject(intf_re->front()));
384         on_loopback = ( rule_iface && rule_iface->isLoopback() );
385     }
386 
387     list<FWObject*> addrlist;
388 
389     for (FWObject::iterator i1=s->begin(); i1!=s->end(); ++i1)
390     {
391         FWObject *o = FWReference::getObject(*i1);
392 	assert(o);
393 
394         Address *addr = Address::cast(o);
395 
396         // this condition includes Host, Firewall and Interface
397         if (addr && !addr->hasInetAddress())
398         {
399             addrlist.push_back(o);
400             continue;
401         }
402 
403         // IPv4, IPv6, Network, NetworkIPv6
404         if (addr && addr->hasInetAddress() && MatchesAddressFamily(o))
405         {
406             addrlist.push_back(o);
407             continue;
408         }
409 
410         if (o->getId() == FWObjectDatabase::ANY_ADDRESS_ID ||
411             MultiAddress::cast(o)!=NULL ||
412             Interface::cast(o) ||
413             physAddress::cast(o))
414         {
415             addrlist.push_back(o);
416             continue;
417         }
418     }
419 
420     if (addrlist.empty())
421     {
422         if (RuleElement::cast(s)==NULL) ol.push_back(s);
423     }
424     else
425     {
426         for (list<FWObject*>::iterator i2=addrlist.begin();
427              i2!=addrlist.end(); ++i2)
428         {
429             Interface *i2itf = Interface::cast(*i2);
430             if (i2itf)
431             {
432 /*
433  * skip copy of the member interface added in CompilerDriver::copyFailoverInterface
434  */
435                 if (i2itf->getBool("member_interface_copy")) continue;
436 
437 /*
438  * Special case is loopback interface - skip it, but only if this rule is
439  * not attached to loopback!
440  *
441  * Correction 10/20/2008: if user put loopback interface object into
442  * rule element, keep it. However if we expanded it from a host or
443  * firewall object, then skip it unless the rule is attached to
444  * loopback interface.
445  */
446                 if (i2itf->isLoopback())
447                 {
448                     if (RuleElement::cast(s) || on_loopback)
449                         _expand_interface(
450                             rule, i2itf, ol, expand_cluster_interfaces_fully);
451                 } else
452 // this is not a loopback interface
453                     _expand_interface(
454                         rule, i2itf, ol, expand_cluster_interfaces_fully);
455 
456                 continue;
457             }
458             _expand_addr_recursive(rule, *i2, ol, expand_cluster_interfaces_fully);
459         }
460     }
461 }
462 
_expand_interface(Rule * rule,Interface * iface,std::list<FWObject * > & ol,bool expand_cluster_interfaces_fully)463 void Compiler::_expand_interface(Rule *rule,
464                                  Interface *iface,
465                                  std::list<FWObject*> &ol,
466                                  bool expand_cluster_interfaces_fully)
467 {
468 /*
469  * if this is an interface with dynamic address, then simply use it
470  * (that is, do not use its children elements "Address")
471  */
472     if (iface->isDyn())
473     {
474         ol.push_back(iface);
475         return;
476     }
477 
478 /*
479  * we use physAddress only if Host option "use_mac_addr_filter" of the
480  * parent Host object is true
481  */
482     FWObject *p = Host::getParentHost(iface);
483     //FWObject *p = iface->getParentHost();
484     Host *hp = Host::cast(p);
485     if (hp==NULL) return;  // something is very broken
486     FWOptions *hopt = hp->getOptionsObject();
487     bool use_mac = (hopt!=NULL && hopt->getBool("use_mac_addr_filter"));
488 
489     for (FWObject::iterator i1=iface->begin(); i1!=iface->end(); ++i1)
490     {
491 	FWObject *o= *i1;
492 
493         if (physAddress::cast(o)!=NULL)
494         {
495             if (use_mac) ol.push_back(o);
496             continue;
497         }
498 
499         // Skip bridge ports
500         Interface *subint = Interface::cast(o);
501         if (subint)
502         {
503             if (subint->isBridgePort()) continue;
504             _expand_interface(rule, subint, ol, expand_cluster_interfaces_fully);
505             continue;
506         }
507 
508         if ( ! iface->isUnnumbered() &&
509              Address::cast(o)!=NULL &&
510              MatchesAddressFamily(o)) ol.push_back(o);
511     }
512 
513     if (expand_cluster_interfaces_fully && iface->isFailoverInterface())
514     {
515         // See #1234  Cluster failover interface expands to its own addresses,
516         // plus addresses of the corresponding member interface
517 
518         FailoverClusterGroup *fg = FailoverClusterGroup::cast(
519             iface->getFirstByType(FailoverClusterGroup::TYPENAME));
520 
521         Interface* member_intf = fg->getInterfaceForMemberFirewall(fw);
522         if (member_intf)
523             _expand_interface(rule, member_intf, ol, expand_cluster_interfaces_fully);
524         else
525         {
526             // per #1394, if the cluster interface used in the rule does not
527             // belong to the cluster being compiled, expand it to its own
528             // address and addresses of all corresponding member interfaces
529             for (FWObjectTypedChildIterator it =
530                      fg->findByType(FWObjectReference::TYPENAME);
531                  it != it.end(); ++it)
532             {
533                 Interface *other_intf = Interface::cast(FWObjectReference::getObject(*it));
534                 assert(other_intf);
535                 _expand_interface(rule, other_intf, ol, expand_cluster_interfaces_fully);
536             }
537         }
538     }
539 }
540 
compare_addresses(FWObject * o1,FWObject * o2)541 bool compare_addresses(FWObject *o1, FWObject *o2)
542 {
543     Address *a1 = Address::cast(o1);
544     Address *a2 = Address::cast(o2);
545     if (a1 == NULL || a2 == NULL)
546     {
547         // one or both could be MultiAddress objects (e.g. DNSName)
548         return o1->getName() < o2->getName();
549     }
550 
551     const InetAddr *addr1 = a1->getAddressPtr();
552     const InetAddr *addr2 = a2->getAddressPtr();
553     if (addr1 == NULL) return true;
554     if (addr2 == NULL) return false;
555     return *addr1 < *addr2;
556 }
557 
558 /**
559  * internal: scans children of 's' and, if found host or firewall with
560  * multiple interfaces, replaces reference to that host or firewall
561  * with a set of references to its interfaces. Argument 's' should be
562  * a pointer at either src or dst in the rule
563  *
564  */
_expand_addr(Rule * rule,FWObject * s,bool expand_cluster_interfaces_fully)565 void Compiler::_expand_addr(Rule *rule, FWObject *s,
566                             bool expand_cluster_interfaces_fully)
567 {
568     list<FWObject*> cl;
569     _expand_addr_recursive(rule, s, cl, expand_cluster_interfaces_fully);
570 
571     list<FWObject*> expanded_addresses;
572     for (FWObject::iterator i=cl.begin(); i!=cl.end(); ++i)
573     {
574         expanded_addresses.push_back(*i);
575     }
576 
577     expanded_addresses.sort(compare_addresses);
578 
579     s->clearChildren();
580 
581     for (list<FWObject*>::iterator i1=expanded_addresses.begin();
582          i1!=expanded_addresses.end(); ++i1)
583     {
584         s->addRef( *i1 );
585     }
586 }
587 
588 /**
589  * replace address range objects in the rule element 're' with series of
590  * regular address obejcts. Drop objects that do not match current
591  * address family.
592  */
_expandAddressRanges(Rule * rule,FWObject * re)593 void Compiler::_expandAddressRanges(Rule *rule, FWObject *re)
594 {
595     list<FWObject*> cl;
596     for (FWObject::iterator i1=re->begin(); i1!=re->end(); ++i1)
597     {
598         FWObject *o = FWReference::getObject(*i1);
599 	assert(o!=NULL);
600 
601         // if this is address range, check if it matches current address
602         // family. If it is not address range, put it back into the rule element
603         // If it is address range but it does not match address family,
604         // throw it away.
605         AddressRange *aro = AddressRange::cast(o);
606 	if (aro)
607         {
608             if (MatchesAddressFamily(o))
609             {
610                 InetAddr a1 = aro->getRangeStart();
611                 InetAddr a2 = aro->getRangeEnd();
612                 vector<InetAddrMask> vn =
613                     libfwbuilder::convertAddressRange(a1,a2);
614 
615                 if (vn.size() == 0)
616                 {
617                     abort(rule,
618                         "Address Range object '" + aro->getName() +
619                         "' can not be converted to set of addresses");
620                 }
621 
622                 for (vector<InetAddrMask>::iterator i=vn.begin();
623                      i!=vn.end(); i++)
624                 {
625                     Network *h = dbcopy->createNetwork();
626                     h->setName(string("%n-")+(*i).toString()+string("%") );
627                     h->setNetmask(*(i->getNetmaskPtr()));
628                     h->setAddress(*(i->getAddressPtr()));
629                     persistent_objects->add(h, false);
630                     cl.push_back(h);
631 
632                     // see GroupRegistry::registerGroupObject()
633                     if (group_registry != NULL)
634                     {
635                         group_registry->setGroupRegistryKey(
636                             h, group_registry->getGroupRegistryKey(aro));
637                     }
638                }
639             }
640 	} else
641         {
642             cl.push_back(o);
643         }
644     }
645 
646     re->clearChildren();
647     for (FWObject::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
648         re->addRef( *i1 );
649 }
650 
normalizePortRange(int & rs,int & re)651 void Compiler::normalizePortRange(int &rs,int &re)
652 {
653     if (rs<0) rs=0;
654     if (re<0) re=0;
655     if (rs!=0 && re==0) re=rs;
656 }
657 
debugRule()658 void Compiler::debugRule()
659 {
660     for (FWObject::iterator i=source_ruleset->begin();
661          i!=source_ruleset->end(); i++)
662     {
663 	Rule *rule = Rule::cast( *i );
664         if (rule == NULL) continue;
665         if (rule_debug_on && rule->getPosition()==debug_rule )
666         {
667             info(debugPrintRule(rule));
668             info("\n");
669         }
670     }
671 }
672 
673 /*
674  *  basic rule printing, not very useful. This method is overloaded in
675  *  derived classes
676  */
debugPrintRule(libfwbuilder::Rule * rule)677 string Compiler::debugPrintRule(libfwbuilder::Rule *rule)
678 {
679     return rule->getLabel();
680 }
681 
682 
683 
684 /**
685  *  adds rule processor to the chain and, if debugging is ON, also
686  *  adds rule processor "Debug" after that. Do not add Debug after
687  *  certain processors, such as SimplePrintProgress
688  */
add(BasicRuleProcessor * rp)689 void Compiler::add(BasicRuleProcessor* rp)
690 {
691     rule_processors.push_back(rp);
692     if (rule_debug_on && dynamic_cast<simplePrintProgress*>(rp)==NULL)
693         rule_processors.push_back(new Debug());
694 }
695 
runRuleProcessors()696 void Compiler::runRuleProcessors()
697 {
698     list<BasicRuleProcessor*>::iterator i=rule_processors.begin();
699     (*i)->setContext(this);
700     list<BasicRuleProcessor*>::iterator j=i;
701     ++i;
702     for ( ; i!=rule_processors.end(); ++i) {
703         (*i)->setContext(this);
704         (*i)->setDataSource( (*j) );
705         j=i;
706     }
707 
708     while ((*j)->processNext()) ;
709 }
710 
deleteRuleProcessors()711 void Compiler::deleteRuleProcessors()
712 {
713     while (rule_processors.size() > 0)
714     {
715         BasicRuleProcessor *rp = rule_processors.front();
716         rule_processors.pop_front();
717         delete rp;
718     }
719 }
720 
Begin()721 Compiler::Begin::Begin() : BasicRuleProcessor("")
722 {
723     init=false;
724 };
725 
Begin(const std::string & n)726 Compiler::Begin::Begin(const std::string &n) : BasicRuleProcessor(n)
727 {
728     init=false;
729 };
730 
processNext()731 bool Compiler::Begin::processNext()
732 {
733     assert(compiler!=NULL);
734     if (!init)
735     {
736         for (FWObject::iterator i=compiler->source_ruleset->begin();
737              i!=compiler->source_ruleset->end(); ++i)
738         {
739             Rule *rule = Rule::cast(*i);
740             if (rule == NULL) continue;
741             if (rule->isDisabled()) continue;
742             if (rule->isDummyRule()) {
743                 compiler->warning(rule, "Rule contains dummy object and is not parsed.");
744                 continue;
745             }
746 
747 
748             Rule  *r = Rule::cast(compiler->dbcopy->create(rule->getTypeName()));
749             compiler->temp_ruleset->add(r);
750             r->duplicate(rule);
751             tmp_queue.push_back( r );
752         }
753         init = true;
754 
755         if (!name.empty()) compiler->info(string(" ") + name);
756 
757         return true;
758     }
759     return false;
760 }
761 
processNext()762 bool Compiler::printTotalNumberOfRules::processNext()
763 {
764     assert(compiler!=NULL);
765     assert(prev_processor!=NULL);
766 
767     slurp();
768     if (tmp_queue.size()==0) return false;
769     if (compiler->verbose)
770     {
771         ostringstream str;
772         str << " processing " << tmp_queue.size() << " rules";
773         compiler->info(str.str());
774     }
775     return true;
776 }
777 
processNext()778 bool Compiler::createNewCompilerPass::processNext()
779 {
780     assert(compiler!=NULL);
781     assert(prev_processor!=NULL);
782 
783     slurp();
784     if (tmp_queue.size()==0) return false;
785     compiler->info(pass_name);
786     return true;
787 }
788 
processNext()789 bool Compiler::Debug::processNext()
790 {
791     assert(compiler!=NULL);
792     assert(prev_processor!=NULL);
793 
794     slurp();
795     if (tmp_queue.size()==0) return false;
796 
797     if (compiler->rule_debug_on)
798     {
799         string n = prev_processor->getName();
800         ostringstream str;
801         str << endl << "--- "  << n << " " << setw(74-n.length()) << setfill('-') << "-";
802         compiler->info(str.str());
803         for (std::deque<Rule*>::iterator i=tmp_queue.begin(); i!=tmp_queue.end(); ++i)
804         {
805             Rule *rule = Rule::cast(*i);
806             if (compiler->rule_debug_on && rule->getPosition()==compiler->debug_rule )
807             {
808                 compiler->info(compiler->debugPrintRule(rule));
809                 compiler->info("\n");
810             }
811         }
812     }
813     return true;
814 }
815 
processNext()816 bool Compiler::singleRuleFilter::processNext()
817 {
818     assert(compiler!=NULL);
819     assert(prev_processor!=NULL);
820 
821     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
822 
823     if (!compiler->single_rule_mode)
824     {
825         tmp_queue.push_back(rule);
826         return true;
827     }
828 
829     if (compiler->single_rule_ruleset_name == compiler->ruleSetName &&
830         rule->getPosition() == compiler->single_rule_position)
831         tmp_queue.push_back(rule);
832 
833     return true;
834 }
835 
processNext()836 bool Compiler::simplePrintProgress::processNext()
837 {
838     Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
839 
840     std::string rl=rule->getLabel();
841     if (rl!=current_rule_label) {
842 
843         if (compiler->verbose) {
844             std::string s=" rule "+rl;
845             compiler->info(s);
846         }
847 
848         current_rule_label=rl;
849     }
850 
851     tmp_queue.push_back(rule);
852     return true;
853 }
854 
855 /**
856  *  re_type can be either RuleElementSrc::TYPENAME or RuleElementDst::TYPENAME
857  *  or some other rule element
858  */
processNext()859 bool Compiler::splitIfRuleElementMatchesFW::processNext()
860 {
861     Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
862 
863     RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
864     int nre = re->size();
865 
866     list<FWObject*> cl;
867 
868     for (list<FWObject*>::iterator i1=re->begin(); nre>1 && i1!=re->end(); ++i1)
869     {
870         FWObject *obj = FWReference::getObject(*i1);
871         Address *a = Address::cast(obj);
872         assert(a!=NULL);
873 
874         if (a->getId() == compiler->fw->getId() ||
875             a->getInt("parent_cluster_id") == compiler->fw->getId() ||
876             compiler->complexMatch(a, compiler->fw))
877         {
878 	    cl.push_back(*i1);
879             nre--;
880 	    Rule  *new_rule = Rule::cast(
881                 compiler->dbcopy->create(rule->getTypeName()) );
882 	    compiler->temp_ruleset->add(new_rule);
883 	    new_rule->duplicate(rule);
884             RuleElement *new_re = RuleElement::cast(
885                 new_rule->getFirstByType(re_type));
886 	    new_re->clearChildren();
887 	    new_re->setAnyElement();
888 	    new_re->addRef( a );
889 	    tmp_queue.push_back(new_rule);
890         }
891 
892     }
893     if (!cl.empty()) {
894         for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
895             re->remove( (*i1) );
896     }
897 
898     tmp_queue.push_back(rule);
899 
900     return true;
901 }
902 
903 /*
904  * This rule processor replaces firewall object in given rule element
905  * with run-time DNSName object with name "self" and source name (A
906  * record) set to "self". This is a trick in that when compliers see
907  * objects like that in a rule, they just put source name in the
908  * generated code verbatim. This is useful for firewall platforms that
909  * support keyword "self" (e.g. PF).
910  *
911  * Always call this RE after splitIfFirewallInSrc or splitIfFirewallInDst
912  */
processNext()913 bool Compiler::ReplaceFirewallObjectWithSelfInRE::processNext()
914 {
915     Rule *rule = prev_processor->getNextRule();
916     if (rule==NULL) return false;
917     RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
918 
919     for (list<FWObject*>::iterator i1=re->begin(); i1!=re->end(); ++i1)
920     {
921         FWObject *obj = FWReference::getObject(*i1);
922         if (obj == compiler->fw)
923         {
924             DNSName *self = DNSName::cast(
925                 compiler->persistent_objects->findObjectByName(
926                     DNSName::TYPENAME, "self"));
927             if (self == NULL)
928             {
929                 self = compiler->dbcopy->createDNSName();
930                 self->setName("self");
931                 self->setRunTime(true);
932                 self->setSourceName("self");
933                 compiler->persistent_objects->add(self, false);
934             }
935 
936             re->addRef(self);
937             re->removeRef(compiler->fw);
938             break;
939         }
940     }
941 
942     tmp_queue.push_back(rule);
943     return true;
944 }
945 
processNext()946 bool Compiler::RegisterGroupsAndTablesInRE::processNext()
947 {
948     Rule *rule = prev_processor->getNextRule();
949     if (rule==NULL) return false;
950 
951     if (compiler->group_registry != NULL)
952     {
953         RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
954 
955         for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
956         {
957             FWObject *obj = FWReference::getObject(*i);
958             if (ObjectGroup::cast(obj)!=NULL && obj->size() > 0)
959             {
960                 compiler->registerGroupObject(re, ObjectGroup::cast(obj));
961             }
962         }
963     }
964 
965     tmp_queue.push_back(rule);
966     return true;
967 }
968 
registerGroupObject(RuleElement * re,ObjectGroup * grp)969 void Compiler::registerGroupObject(RuleElement *re, ObjectGroup *grp)
970 {
971     assert(group_registry!=NULL);
972     list<FWObject*> objects;
973     expandGroup(grp, objects);
974     group_registry->registerGroup(grp, objects);
975     group_registry->registerGroupInRE(re, grp);
976 }
977 
operator ()(FWObject * o)978 bool Compiler::equalObj::operator()(FWObject *o)
979 {
980     return o->getId()==obj->getId();
981 }
982 
processNext()983 bool Compiler::singleObjectNegation::processNext()
984 {
985     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
986 
987     RuleElement *rel = RuleElement::cast(rule->getFirstByType(re_type));
988     assert(rel);
989 
990     if (rel->getNeg() && rel->size()==1)
991     {
992         if (rel->getTypeName() == RuleElementItfInb::TYPENAME ||
993             rel->getTypeName() == RuleElementItfOutb::TYPENAME ||
994             rel->getTypeName() == RuleElementItf::TYPENAME )
995         {
996             rel->setNeg(false);
997             rel->setBool("single_object_negation", true);
998         } else
999         {
1000             FWObject *o = rel->front();
1001             if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
1002             Address *reladdr = Address::cast(o);
1003             if ( reladdr && reladdr->countInetAddresses(true)==1 &&
1004                  !compiler->complexMatch(reladdr, compiler->fw))
1005             {
1006                 rel->setNeg(false);
1007                 rel->setBool("single_object_negation", true);
1008             }
1009         }
1010     }
1011 
1012     tmp_queue.push_back(rule);
1013     return true;
1014 }
1015 
1016 
1017 /*
1018  * Process negation in the "Interface" rule element. Scan objects in
1019  * this RE, replace cluster interfaces with interfaces of the member,
1020  * then replace them with a list of all other interfaces of the member.
1021  *
1022  * Note that normally compiler should call
1023  * replaceClusterInterfaceInItf before calling this processor. This
1024  * means that this processor should never see cluster interfaces in
1025  * the RE. However I keep the code that deals with them in place to be
1026  * able to use this processor without prior call to
1027  * replaceClusterInterfaceInItf if necessary.
1028  *
1029  * TODO: make this code assert() if cluster interface appears in RE/
1030  *
1031  * Note that rule processor singleObjectNegationItf deals with single
1032  * object negation in Interface rule elements.
1033  */
processNext()1034 bool Compiler::fullInterfaceNegationInRE::processNext()
1035 {
1036     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1037     RuleElement *itfre = RuleElement::cast(rule->getFirstByType(re_type));
1038 
1039     if (itfre==NULL)
1040         compiler->abort(rule, "Missing interface rule element");
1041 
1042     FWOptions *fwopt = compiler->getCachedFwOpt();
1043 
1044     if (itfre->getNeg())
1045     {
1046         // Use getByTypeDeep() to pick subinterfaces (vlans and such)
1047         list<FWObject*> all_interfaces =
1048             compiler->fw->getByTypeDeep(Interface::TYPENAME);
1049         list<FWObject*> work_interfaces;
1050 
1051         // skip unprotected interfaces bug #2710034 "PF Compiler in 3.0.3
1052         // Unprotected Interface Bug"
1053         for (FWObject::iterator i=all_interfaces.begin(); i!=all_interfaces.end(); ++i)
1054         {
1055             Interface *intf = Interface::cast(*i);
1056             if (intf == NULL) continue;
1057             if (intf->isUnprotected()) continue;
1058             if (intf->isLoopback()) continue;
1059 
1060             // skip bridge ports, but use them if this is bridging firewall
1061             if ( ! fwopt->getBool("bridging_fw") && intf->isBridgePort()) continue;
1062 
1063             if (intf->getOptionsObject()->getBool("cluster_interface")) continue;
1064             work_interfaces.push_back(intf);
1065         }
1066 
1067         for (FWObject::iterator i=itfre->begin(); i!=itfre->end(); ++i)
1068         {
1069             // Only interface objects are allowed in the "Interface" rule element
1070             Interface *rule_iface = Interface::cast(FWReference::getObject(*i));
1071             if (rule_iface == NULL) continue;
1072             // If this interface belongs to a cluster (which can only happen
1073             // if the rule set belongs to  a cluster), then replace it with
1074             // corresponding interface of the member
1075             if (rule_iface->isFailoverInterface())
1076             {
1077                 FailoverClusterGroup *fg = FailoverClusterGroup::cast(
1078                     rule_iface->getFirstByType(FailoverClusterGroup::TYPENAME));
1079                 if (fg)
1080                     rule_iface = fg->getInterfaceForMemberFirewall(compiler->fw);
1081             }
1082             if (rule_iface) work_interfaces.remove(rule_iface);
1083         }
1084 
1085         itfre->reset();
1086         itfre->setNeg(false);
1087         FWObject::iterator i;
1088         for (i=work_interfaces.begin(); i!=work_interfaces.end(); ++i)
1089             itfre->addRef(*i);
1090     }
1091 
1092     tmp_queue.push_back(rule);
1093     return true;
1094 }
1095 
1096 /*
1097  * Call this processor before ItfNegation (and in some compilers,
1098  * singleItfNegation).
1099  */
processNext()1100 bool Compiler::replaceClusterInterfaceInItfRE::processNext()
1101 {
1102     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1103     RuleElement *itfre = RuleElement::cast(rule->getFirstByType(re_type));
1104     if (itfre==NULL)
1105         compiler->abort(rule, "Missing interface rule element");
1106 
1107     map<FWObject*, FWObject*> interface_replacement;
1108 
1109     for (FWObject::iterator i=itfre->begin(); i!=itfre->end(); ++i)
1110     {
1111         Interface *member_iface = NULL;
1112 
1113         // Only interface objects are allowed in the "Interface" rule element
1114         FWObject *o = FWReference::getObject(*i);
1115         Interface *rule_iface = Interface::cast(o);
1116         if (rule_iface == NULL) continue;
1117         // If this interface belongs to a cluster (which can only happen
1118         // if the rule set belongs to  a cluster), then replace it with
1119         // corresponding interface of the member
1120         if (rule_iface->isFailoverInterface())
1121         {
1122             FailoverClusterGroup *fg = FailoverClusterGroup::cast(
1123                 rule_iface->getFirstByType(FailoverClusterGroup::TYPENAME));
1124             if (fg)
1125                 member_iface = fg->getInterfaceForMemberFirewall(compiler->fw);
1126         }
1127         if (member_iface)
1128         {
1129             interface_replacement[rule_iface] = member_iface;
1130         }
1131     }
1132 
1133     map<FWObject*, FWObject*>::iterator r;
1134     for (r = interface_replacement.begin(); r != interface_replacement.end(); ++r)
1135     {
1136         itfre->removeRef(r->first);
1137         itfre->addRef(r->second);
1138     }
1139 
1140     itfre->sort(FWObjectNameCmpPredicate(true));
1141 
1142     tmp_queue.push_back(rule);
1143     return true;
1144 }
1145 
processNext()1146 bool Compiler::eliminateDuplicatesInRE::processNext()
1147 {
1148     Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
1149 
1150     if (comparator==NULL) comparator = new equalObj();
1151 
1152     RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
1153 
1154     list<FWObject*> cl;
1155 
1156     for(list<FWObject*>::iterator i=re->begin(); i!=re->end(); ++i)
1157     {
1158         FWObject *obj = FWReference::getObject(*i);
1159         if (obj == NULL) continue;
1160 
1161         comparator->set(obj);
1162 
1163         bool found = false;
1164         for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
1165         {
1166             FWObject *o2 = *i1;
1167             if ( (*comparator)(o2) ) { found=true; break; }
1168         }
1169         if (!found) cl.push_back(obj);
1170     }
1171     if (!cl.empty())
1172     {
1173         re->clearChildren();
1174         for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
1175             re->addRef( (*i1) );
1176     }
1177 
1178     tmp_queue.push_back(rule);
1179 
1180     return true;
1181 }
1182 
isRecursiveGroup(int grid,FWObject * obj)1183 void  Compiler::recursiveGroupsInRE::isRecursiveGroup(int grid, FWObject *obj)
1184 {
1185     for (FWObject::iterator i=obj->begin(); i!=obj->end(); i++)
1186     {
1187         FWObject *o = FWReference::getObject(*i);
1188         if (Group::cast(o)!=NULL)
1189         {
1190             if (o->getId()==grid || obj->getId()==o->getId())
1191             {
1192                 compiler->abort(
1193 
1194                         "Group '" + o->getName() + "' references itself recursively");
1195             }
1196             isRecursiveGroup(grid,o);
1197             isRecursiveGroup(o->getId(),o);
1198         }
1199     }
1200 }
1201 
processNext()1202 bool Compiler::recursiveGroupsInRE::processNext()
1203 {
1204     Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
1205     RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
1206 
1207     if (re == NULL || re->isAny())
1208     {
1209         tmp_queue.push_back(rule);
1210         return true;
1211     }
1212 
1213     std::list<FWObject*> cl;
1214     for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
1215     {
1216         FWObject *o = FWReference::getObject(*i);
1217         if (Group::cast(o)!=NULL)  isRecursiveGroup(o->getId(),o);
1218     }
1219 
1220     tmp_queue.push_back(rule);
1221     return true;
1222 }
1223 
1224 
1225 /*
1226  *  counts children of obj recursively (that is, its direct children objects, plus
1227  *  their children objects, etc.
1228  */
countChildren(FWObject * obj)1229 int  Compiler::emptyGroupsInRE::countChildren(FWObject *obj)
1230 {
1231     if (obj->size()==0) return 0;
1232     int n=0;
1233     for (FWObject::iterator i=obj->begin(); i!=obj->end(); i++)
1234     {
1235         FWObject *o = FWReference::getObject(*i);
1236 
1237         // Check if this is a group, if yes, then count its children
1238         // recursively. Group itself does not count since it can be
1239         // empty, too.  However if this is MultiAddress object with
1240         // run-time processing, it does not count as an empty group
1241         // since we have no way to know at compile time if it will
1242         // have some addresses at run time. So we just count it as a
1243         // regular object.
1244 
1245         if (MultiAddress::cast(o)!=NULL && MultiAddress::cast(o)->isRunTime())
1246             n++;
1247         else
1248         {
1249             if (Group::cast(o)!=NULL)  n += countChildren(o);
1250             else n++;   // but if it is not a group, then we count it.
1251         }
1252     }
1253     return n;
1254 }
1255 
processNext()1256 bool Compiler::emptyGroupsInRE::processNext()
1257 {
1258     Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
1259     RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
1260 
1261     if (re == NULL || re->isAny())
1262     {
1263         tmp_queue.push_back(rule);
1264         return true;
1265     }
1266 
1267     std::list<FWObject*> cl;
1268     for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
1269     {
1270         FWObject *o = FWReference::getObject(*i);
1271 
1272         if ( MultiAddress::cast(o)!=NULL && MultiAddress::cast(o)->isRunTime())
1273             continue;
1274 
1275         if (Group::cast(o)!=NULL && countChildren(o)==0)
1276             cl.push_back(o);
1277     }
1278 
1279     if (!cl.empty())
1280     {
1281         if ( compiler->fw->getOptionsObject()->getBool ("ignore_empty_groups") )
1282         {
1283             for (FWObject::iterator i=cl.begin(); i!=cl.end(); i++)
1284             {
1285                 FWObject *o= *i;
1286                 ostringstream  str;
1287                 str << "Empty group or address table object '"
1288                     << o->getName()
1289                     << "'";
1290                 re->removeRef(o);
1291                 compiler->warning(rule, str.str());
1292             }
1293             if (re->isAny())
1294             {
1295                 ostringstream  str;
1296                 str << "After removal of all empty groups and address table objects rule element "
1297                     << re->getTypeName()
1298                     << " becomes 'any' in the rule "
1299                     << rule->getLabel()
1300                     << endl
1301                     << "Dropping rule "
1302                     <<  rule->getLabel()
1303                     << " because option 'Ignore rules with empty groups' is in effect";
1304                 compiler->warning(rule,  str.str());
1305 
1306                 return true; // dropping this rule
1307             }
1308         } else
1309         {
1310             std::string gr;
1311             int cntr = 0;
1312             for (FWObject::iterator i=cl.begin(); i!=cl.end(); i++)
1313             {
1314                 FWObject *o= *i;
1315                 if (cntr>0) gr += ",";
1316                 gr += o->getName();
1317                 cntr++;
1318             }
1319 
1320             ostringstream  str;
1321             str << "Empty group or address table object"
1322                 << " '"
1323                 << gr
1324                 << "' is used in the rule"
1325                 << " but option 'Ignore rules with empty groups' is off";
1326             compiler->abort(rule, str.str());
1327         }
1328     }
1329     tmp_queue.push_back(rule);
1330     return true;
1331 }
1332 
1333 
1334 /**
1335  * swaps MultiAddress objects that require run-time expansion with
1336  * MultiAddressRunTime equivalents
1337  */
processNext()1338 bool Compiler::swapMultiAddressObjectsInRE::processNext()
1339 {
1340     Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
1341 
1342     RuleElement *re=RuleElement::cast( rule->getFirstByType(re_type) );
1343     if (re == NULL || re->isAny())
1344     {
1345         tmp_queue.push_back(rule);
1346         return true;
1347     }
1348 
1349     list<MultiAddress*> cl;
1350     for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
1351     {
1352         FWObject *o = FWReference::getObject(*i);
1353         if (MultiAddress::cast(o)!=NULL && MultiAddress::cast(o)->isRunTime())
1354             cl.push_back(MultiAddress::cast(o));
1355     }
1356 
1357     if (!cl.empty())
1358     {
1359         for (list<MultiAddress*>::iterator i=cl.begin(); i!=cl.end(); i++)
1360         {
1361             MultiAddress *ma = *i;
1362 
1363             // Need to make sure the ID of the MultiAddressRunTime
1364             // object created here is stable and is always the same
1365             // for the same MultiAddress object. In particular this
1366             // ensures that we reuse tables between policy and NAT rules
1367             // in compiler for PF. There could be other similar cases
1368             // (object-group in compielr for pix may be ?)
1369             string mart_id_str = FWObjectDatabase::getStringId(ma->getId()) +
1370                 "_runtime";
1371             int mart_id = FWObjectDatabase::registerStringId(mart_id_str);
1372             MultiAddressRunTime *mart = MultiAddressRunTime::cast(
1373                 compiler->dbcopy->findInIndex(mart_id));
1374             if (mart==NULL)
1375             {
1376                 mart = new MultiAddressRunTime(ma);
1377 
1378                 // need to ensure stable ID for the runtime object, so
1379                 // that when the same object is replaced in different
1380                 // rulesets by different compiler passes, chosen
1381                 // runtime object has the same ID and is identified as
1382                 // the same by the compiler.
1383 
1384                 mart->setId( mart_id );
1385                 compiler->dbcopy->addToIndex(mart);
1386                 compiler->persistent_objects->add(mart);
1387             }
1388             re->removeRef(ma);
1389             re->addRef(mart);
1390         }
1391         tmp_queue.push_back(rule);
1392         return true;
1393     }
1394 
1395     tmp_queue.push_back(rule);
1396     return true;
1397 }
1398 
processNext()1399 bool Compiler::expandMultipleAddressesInRE::processNext()
1400 {
1401     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1402     RuleElement *re = RuleElement::cast( rule->getFirstByType(re_type) );
1403     if (re) compiler->_expand_addr(rule, re, true);
1404     tmp_queue.push_back(rule);
1405     return true;
1406 }
1407 
1408 
processNext()1409 bool Compiler::checkForObjectsWithErrors::processNext()
1410 {
1411     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1412 
1413     for (FWObject::iterator it1=rule->begin(); it1!=rule->end(); it1++)
1414     {
1415         RuleElement *re = RuleElement::cast(*it1);
1416         if (re == NULL || re->isAny()) continue;
1417         for (FWObject::iterator it2=re->begin(); it2!=re->end(); it2++)
1418         {
1419             FWObject *obj = FWReference::getObject(*it2);
1420             if (obj->getBool(".rule_error"))
1421             {
1422                 // it is ok to call abort this late in rule
1423                 // processing.  If the error was fatal, the code that
1424                 // encounter it should have called abort() then. If it
1425                 // continued, then we are in test mode and this call to
1426                 // abort will continue too. In the worst case, we end up
1427                 // with duplicate error messages in the test mode.
1428                 compiler->abort(rule, obj->getStr(".error_msg"));
1429             }
1430         }
1431     }
1432 
1433     tmp_queue.push_back(rule);
1434     return true;
1435 }
1436 
1437 
processNext()1438 bool Compiler::replaceFailoverInterfaceInRE::processNext()
1439 {
1440     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1441     RuleElement *re = RuleElement::cast( rule->getFirstByType(re_type) );
1442 
1443     if (re == NULL || re->isAny())
1444     {
1445         tmp_queue.push_back(rule);
1446         return true;
1447     }
1448 
1449     // list of pointers to cluster interfaces used in the RE
1450     list<Interface*> cl;
1451     for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
1452     {
1453         Interface *intf = Interface::cast(FWReference::getObject(*i));
1454         if (intf==NULL) continue;
1455 
1456         if (intf->isFailoverInterface()) cl.push_back(intf);
1457         else
1458         {
1459             // this could be a copy of cluster interface which belongs
1460             // to the firewall. This is done in
1461             // Compiler::processFailoverGroup. Dont use interface name
1462             // to distinguish cluster interface. Better method is to
1463             // check for the variable "cluster_interface".
1464             if (intf->getOptionsObject()->getBool("cluster_interface"))
1465                 cl.push_back(intf);
1466         }
1467     }
1468 
1469     if (!cl.empty())
1470     {
1471         for (list<Interface*>::iterator i=cl.begin(); i!=cl.end(); i++)
1472         {
1473             Interface *intf = *i;
1474 
1475             FailoverClusterGroup *fg = FailoverClusterGroup::cast(
1476                 intf->getFirstByType(FailoverClusterGroup::TYPENAME));
1477             if (fg)
1478             {
1479                 Interface *other_interface = fg->getInterfaceForMemberFirewall(compiler->fw);
1480                 re->removeRef(intf);
1481                 re->addRef(other_interface);
1482             } else
1483             {
1484                 string base_interface_id = intf->getOptionsObject()->getStr("base_interface_id");
1485                 if (!base_interface_id.empty())
1486                 {
1487                     FWObject *base_interface = compiler->dbcopy->findInIndex(
1488                         FWObjectDatabase::getIntId(base_interface_id));
1489                     if (base_interface)
1490                     {
1491                         re->removeRef(intf);
1492                         re->addRef(base_interface);
1493                     }
1494                 }
1495             }
1496         }
1497     }
1498     tmp_queue.push_back(rule);
1499     return true;
1500 }
1501 
FindAddressFamilyInRE(FWObject * parent,bool ipv6)1502 bool Compiler::FindAddressFamilyInRE(FWObject *parent, bool ipv6)
1503 {
1504     Address *addr = Address::cast(parent);
1505     if (addr!=NULL)
1506     {
1507         const  InetAddr *inet_addr = addr->getAddressPtr();
1508         if (ipv6)
1509             return (inet_addr && inet_addr->isV6());
1510         else
1511             return (inet_addr && inet_addr->isV4());
1512     }
1513 
1514     for (FWObject::iterator i=parent->begin(); i!=parent->end(); i++)
1515     {
1516         FWObject *o = FWReference::getObject(*i);
1517         if (FindAddressFamilyInRE(o, ipv6)) return true;
1518     }
1519     return false;
1520 }
1521 
1522 
DropAddressFamilyInRE(RuleElement * rel,bool drop_ipv6)1523 void Compiler::DropAddressFamilyInRE(RuleElement *rel, bool drop_ipv6)
1524 {
1525     list<FWObject*> objects_to_remove;
1526     for (FWObject::iterator i=rel->begin(); i!=rel->end(); i++)
1527     {
1528         FWObject *o = FWReference::getObject(*i);
1529         // skip "Any"
1530         if (o->getId() == FWObjectDatabase::ANY_ADDRESS_ID) continue;
1531 
1532         if (Address::cast(o) && Address::cast(o)->hasInetAddress())
1533         {
1534             const  InetAddr *inet_addr = Address::cast(o)->getAddressPtr();
1535             if (inet_addr)
1536             {
1537                 if (drop_ipv6 && inet_addr->isV6())
1538                     objects_to_remove.push_back(o);
1539 
1540                 if (!drop_ipv6 && inet_addr->isV4())
1541                     objects_to_remove.push_back(o);
1542             }
1543         }
1544     }
1545 
1546     for (list<FWObject*>::iterator i = objects_to_remove.begin();
1547          i != objects_to_remove.end(); ++i)
1548         rel->removeRef(*i);
1549 }
1550 
isREEmpty(Rule * rule,const std::string & re_type)1551 bool Compiler::dropRuleWithEmptyRE::isREEmpty(Rule *rule,
1552                                               const std::string &re_type)
1553 {
1554     RuleElement *re = RuleElement::cast(rule->getFirstByType(re_type));
1555     return re->size()==0;
1556 }
1557 
1558 /*
1559  * TODO: why rule elements Service, Interface and Time are not checked
1560  * for policy rules?
1561  */
processNext()1562 bool Compiler::dropRuleWithEmptyRE::processNext()
1563 {
1564     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1565 
1566     if (PolicyRule::cast(rule) &&
1567         (isREEmpty(rule, RuleElementSrc::TYPENAME) ||
1568          isREEmpty(rule, RuleElementDst::TYPENAME)))
1569     {
1570         if (!warning_str.empty()) compiler->warning(rule, warning_str);
1571         return true;
1572     }
1573 
1574     if (NATRule::cast(rule) &&
1575         (isREEmpty(rule, RuleElementOSrc::TYPENAME) ||
1576          isREEmpty(rule, RuleElementODst::TYPENAME) ||
1577          isREEmpty(rule, RuleElementOSrv::TYPENAME) ||
1578          isREEmpty(rule, RuleElementTSrc::TYPENAME) ||
1579          isREEmpty(rule, RuleElementTDst::TYPENAME) ||
1580          isREEmpty(rule, RuleElementTSrv::TYPENAME)))
1581     {
1582         if (!warning_str.empty())compiler->warning(rule, warning_str);
1583         return true;
1584     }
1585 
1586     if (RoutingRule::cast(rule) &&
1587         (isREEmpty(rule, RuleElementRDst::TYPENAME) ||
1588          isREEmpty(rule, RuleElementRGtw::TYPENAME) ||
1589          isREEmpty(rule, RuleElementRItf::TYPENAME)))
1590     {
1591         if (!warning_str.empty()) compiler->warning(rule, warning_str);
1592         return true;
1593     }
1594 
1595     tmp_queue.push_back(rule);
1596     return true;
1597 }
1598 
1599 
1600 
DropByServiceTypeInRE(RuleElement * rel,bool drop_ipv6)1601 void Compiler::DropByServiceTypeInRE(RuleElement *rel, bool drop_ipv6)
1602 {
1603     list<FWObject*> objects_to_remove;
1604     for (FWObject::iterator i=rel->begin(); i!=rel->end(); i++)
1605     {
1606         FWObject *o = FWReference::getObject(*i);
1607         // skip "Any"
1608         if (o->getId() == FWObjectDatabase::ANY_SERVICE_ID) continue;
1609 
1610         Service *svc = Service::cast(o);
1611 
1612         if (svc == NULL)
1613         {
1614             cerr << endl;
1615             cerr << "Rule " << Rule::cast(rel->getParent())->getLabel()
1616                  << "  Rule element " << rel->getTypeName()
1617                  << endl;
1618             o->dump(true, false);
1619         }
1620 
1621         assert(svc);
1622 
1623         // Note that all service objects except for ICMPService and
1624         // CustomService can be used in both ipv4 and ipv6 contexts.
1625         if (drop_ipv6)
1626         {
1627             if (svc->isV6Only()) objects_to_remove.push_back(o);
1628         } else
1629         {
1630             if (svc->isV4Only()) objects_to_remove.push_back(o);
1631         }
1632     }
1633 
1634     for (list<FWObject*>::iterator i = objects_to_remove.begin();
1635          i != objects_to_remove.end(); ++i)
1636         rel->removeRef(*i);
1637 }
1638 
catchUnnumberedIfaceInRE(RuleElement * re)1639 bool Compiler::catchUnnumberedIfaceInRE(RuleElement *re)
1640 {
1641     bool err = false;
1642     Interface *iface;
1643     for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
1644     {
1645         FWObject *o = FWReference::getObject(*i);
1646         if (o==NULL)
1647         {
1648             //Rule *rule = Rule::cast(re->getParent());
1649             FWReference *refo = FWReference::cast(*i);
1650             string errmsg =
1651                 string("catchUnnumberedIfaceInRE: Can't find object ") +
1652                 string("in cache, ID=") +
1653                 FWObjectDatabase::getStringId(refo->getPointerId());
1654             abort(re->getParent(), errmsg);
1655         }
1656         err |= ((iface=Interface::cast(o))!=NULL &&
1657                 (iface->isUnnumbered() || iface->isBridgePort())
1658         );
1659     }
1660     return err;
1661 }
1662 
getFirstSrc(PolicyRule * rule)1663 Address* Compiler::getFirstSrc(PolicyRule *rule)
1664 {
1665     RuleElementSrc *src = rule->getSrc();
1666     FWObject *o = FWReference::getObject(src->front());
1667     return Address::cast(o);
1668 }
1669 
getFirstDst(PolicyRule * rule)1670 Address* Compiler::getFirstDst(PolicyRule *rule)
1671 {
1672     RuleElementDst *dst = rule->getDst();
1673     FWObject *o = FWReference::getObject(dst->front());
1674     return Address::cast(o);
1675 }
1676 
getFirstSrv(PolicyRule * rule)1677 Service* Compiler::getFirstSrv(PolicyRule *rule)
1678 {
1679     RuleElementSrv *srv = rule->getSrv();
1680     FWObject *o = FWReference::getObject(srv->front());
1681     return Service::cast(o);
1682 }
1683 
getFirstWhen(PolicyRule * rule)1684 Interval* Compiler::getFirstWhen(PolicyRule *rule)
1685 {
1686     RuleElementInterval *when = rule->getWhen();
1687     if (when==NULL) return NULL;  // when is optional element
1688     FWObject *o = FWReference::getObject(when->front());
1689     return Interval::cast(o);
1690 }
1691 
getFirstItf(PolicyRule * rule)1692 Interface* Compiler::getFirstItf(PolicyRule *rule)
1693 {
1694     RuleElementItf *itf = rule->getItf();
1695     if (itf==NULL || itf->size()==0) return NULL;  // itf is optional element
1696     FWObject *o = FWReference::getObject(itf->front());
1697     return Interface::cast(o);
1698 }
1699 
getFirstOSrc(NATRule * rule)1700 Address* Compiler::getFirstOSrc(NATRule *rule)
1701 {
1702     RuleElementOSrc *osrc = rule->getOSrc();
1703     assert(osrc!=NULL);
1704     FWObject *o = FWReference::getObject(osrc->front());
1705     return Address::cast(o);
1706 }
1707 
getFirstODst(NATRule * rule)1708 Address* Compiler::getFirstODst(NATRule *rule)
1709 {
1710     RuleElementODst *odst = rule->getODst();
1711     assert(odst!=NULL);
1712     FWObject *o = FWReference::getObject(odst->front());
1713     return Address::cast(o);
1714 }
1715 
getFirstOSrv(NATRule * rule)1716 Service* Compiler::getFirstOSrv(NATRule *rule)
1717 {
1718     RuleElementOSrv *osrv = rule->getOSrv();
1719     assert(osrv!=NULL);
1720     FWObject *o = FWReference::getObject(osrv->front());
1721     return Service::cast(o);
1722 }
1723 
getFirstTSrc(NATRule * rule)1724 Address* Compiler::getFirstTSrc(NATRule *rule)
1725 {
1726     RuleElementTSrc *tsrc = rule->getTSrc();
1727     assert(tsrc!=NULL);
1728     FWObject *o = FWReference::getObject(tsrc->front());
1729     return Address::cast(o);
1730 }
1731 
getFirstTDst(NATRule * rule)1732 Address* Compiler::getFirstTDst(NATRule *rule)
1733 {
1734     RuleElementTDst *tdst = rule->getTDst();
1735     assert(tdst!=NULL);
1736     FWObject *o = FWReference::getObject(tdst->front());
1737     return Address::cast(o);
1738 }
1739 
getFirstTSrv(NATRule * rule)1740 Service* Compiler::getFirstTSrv(NATRule *rule)
1741 {
1742     RuleElementTSrv *tsrv = rule->getTSrv();
1743     assert(tsrv!=NULL);
1744     FWObject *o = FWReference::getObject(tsrv->front());
1745     return Service::cast(o);
1746 }
1747 
1748 /*
1749  * Compares given object with firewall or its parent cluster (if any).
1750  * Compares only IDs of these objects. Relies on class CompilerDriver
1751  * to set integer variable "parent_cluster_id" in the firewall object
1752  * if it is a member of a cluster.
1753  */
isFirewallOrCluster(FWObject * obj)1754 bool Compiler::isFirewallOrCluster(FWObject *obj)
1755 {
1756     int fw_id = fw->getId();
1757     int cluster_id = fw->getInt("parent_cluster_id");
1758     return obj->getId() == fw_id || obj->getId() == cluster_id;
1759 }
1760 
printComment(Rule * rule,string & prev_rule_label,const std::string & prefix,bool suppress_comment)1761 string Compiler::printComment(Rule *rule, string &prev_rule_label,
1762                               const std::string &prefix, bool suppress_comment)
1763 {
1764     ostringstream res;
1765     string rl = rule->getLabel();
1766     if (rl != prev_rule_label)
1767     {
1768         if ( ! inSingleRuleCompileMode())
1769         {
1770             res << prefix << " " << endl;
1771             res << prefix << " Rule  " << rl << endl;
1772         }
1773         string comm = rule->getComment();
1774         if ( ! suppress_comment && ! comm.empty())
1775         {
1776             string::size_type c1, c2;
1777             c1 = 0;
1778             while ( (c2 = comm.find('\n', c1)) != string::npos )
1779             {
1780                 res << prefix << " " << comm.substr(c1, c2 - c1) << endl;
1781                 c1 = c2 + 1;
1782             }
1783             string remainder =  comm.substr(c1);
1784             if (!remainder.empty())
1785                 res << prefix << " " << remainder << endl;
1786         }
1787 
1788         string err = getErrorsForRule(rule, prefix + " ");
1789         if (!err.empty()) res << err << endl;
1790 
1791         prev_rule_label = rl;
1792     }
1793 //    string err = rule->getCompilerMessage();
1794 //    if (!err.empty()) res << prefix << " " << err << endl;
1795     return res.str();
1796 }
1797 
correctForCluster(Address * addr)1798 Address* Compiler::correctForCluster(Address *addr)
1799 {
1800 #ifdef DEBUG_FOR_DMZ
1801     cerr << "Compiler::correctForCluster " << addr << endl;
1802     if (addr)
1803     {
1804         cerr << "  addr: " << addr->getName() << endl;
1805     }
1806 #endif
1807 
1808     Interface *intf = Interface::cast(addr);
1809 
1810     if (intf)
1811     {
1812 #ifdef DEBUG_FOR_DMZ
1813         cerr << "    intf: " << intf->getName()
1814              << "    isFailoverInterface: " << intf->isFailoverInterface()
1815              << endl;
1816 #endif
1817     }
1818 
1819     if (intf && intf->isFailoverInterface())
1820     {
1821         FailoverClusterGroup *fg = FailoverClusterGroup::cast(
1822             intf->getFirstByType(FailoverClusterGroup::TYPENAME));
1823         if (fg)
1824         {
1825             Address *other_intf = fg->getInterfaceForMemberFirewall(fw);
1826 #ifdef DEBUG_FOR_DMZ
1827             cerr << "    fg: " << fg->getName() << endl;
1828             cerr << "    other_intf: " << other_intf << endl;
1829 #endif
1830             if (other_intf) return other_intf;
1831         }
1832     }
1833     return addr;
1834 }
1835 
1836 /* keep only rules that have ipv4 addresses in src and dst
1837  *
1838  * This rule processor assumes all groups and multi-address objects
1839  * have already been expanded.
1840  *
1841  * TODO: figure out what to do with rules that have mix of ipv4 and ipv6
1842  * addresses in different rule elements (such as ipv4 address in odst
1843  * and ipv6 address in tdst or similar)
1844  */
processNext()1845 bool Compiler::DropRulesByAddressFamilyAndServiceType::processNext()
1846 {
1847     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
1848 
1849     for(FWObject::iterator it=rule->begin(); it!=rule->end(); ++it)
1850     {
1851         RuleElement *re = RuleElement::cast(*it);
1852         if (re == NULL) continue;  // probably RuleOptions object
1853 
1854         bool orig_any = re->isAny();
1855         if (orig_any) continue;
1856 
1857         FWObject *first_object = FWReference::getObject(re->front());
1858         if (Address::cast(first_object) != NULL)
1859             compiler->DropAddressFamilyInRE(re, drop_ipv6);
1860 
1861         if (Service::cast(first_object) != NULL)
1862             compiler->DropByServiceTypeInRE(re, drop_ipv6);
1863 
1864         if (!orig_any && re->isAny())
1865         {
1866             // removing all ipv6 addresses from rule element makes it 'any', drop
1867             // this rule
1868             if (!warning_str.empty()) compiler->warning(rule, warning_str);
1869             return true;
1870         }
1871     }
1872 
1873     tmp_queue.push_back(rule);
1874 
1875     return true;
1876 }
1877 
1878 
1879