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