1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2002-2011 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 
26 #include "NATCompiler_pix.h"
27 #include "NamedObjectsAndGroupsSupport.h"
28 #include "NamedObjectsManager.h"
29 
30 #include "fwbuilder/FWObjectDatabase.h"
31 #include "fwbuilder/RuleElement.h"
32 #include "fwbuilder/NAT.h"
33 #include "fwbuilder/AddressRange.h"
34 #include "fwbuilder/ICMPService.h"
35 #include "fwbuilder/TCPService.h"
36 #include "fwbuilder/UDPService.h"
37 #include "fwbuilder/Interface.h"
38 #include "fwbuilder/IPv4.h"
39 #include "fwbuilder/IPv6.h"
40 #include "fwbuilder/InetAddr.h"
41 #include "fwbuilder/Network.h"
42 #include "fwbuilder/Resources.h"
43 #include "fwbuilder/AddressTable.h"
44 #include "fwbuilder/Cluster.h"
45 #include "fwbuilder/FailoverClusterGroup.h"
46 
47 #include <assert.h>
48 
49 #include <QString>
50 
51 
52 using namespace libfwbuilder;
53 using namespace fwcompiler;
54 using namespace std;
55 
56 
57 
58 /*
59  * this processor uses slurp to make sure all previous processors ran before
60  * it starts scanning rules.
61  */
processNext()62 bool NATCompiler_pix::mergeNATCmd::processNext()
63 {
64     NATCompiler_pix *pix_comp = dynamic_cast<NATCompiler_pix*>(compiler);
65 
66     slurp();
67     if (tmp_queue.size()==0) return false;
68 
69     for (deque<Rule*>::iterator k=tmp_queue.begin(); k!=tmp_queue.end(); ++k)
70     {
71         NATRule *rule = NATRule::cast( *k );
72 
73         if (rule->getRuleType() == NATRule::DNAT)
74         {
75             StaticCmd *scmd = pix_comp->static_commands[rule->getInt("sc_cmd")];
76 
77             map<int,StaticCmd*>::iterator i1;
78             for (i1=pix_comp->static_commands.begin();
79                  i1!=pix_comp->static_commands.end(); ++i1)
80             {
81                 StaticCmd *sc = (*i1).second;
82                 if (scmd==sc) break;
83 
84                 if ( *scmd == *sc)
85                 {
86 /*
87  * rule 'sc' is above rule 'scmd', we need to print 'static' command
88  * only in the last rule using the same access list. That's why we set
89  * flag ignore_scmd_and_print acl in sc and not in scmd
90  */
91                     scmd->acl_name = sc->acl_name;
92                     sc->ignore_scmd_and_print_acl = true;
93                 }
94             }
95         }
96 
97 	if (rule->getRuleType()==NATRule::SNAT)
98         {
99             NATCmd *natcmd = pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
100 
101             map<int,NATCmd*>::iterator i1;
102             for (i1 = pix_comp->nat_commands.begin();
103                  i1 != pix_comp->nat_commands.end(); ++i1)
104             {
105                 NATCmd *nc = (*i1).second;
106 /* since map nat_commands is sorted by the key, we only have to scan it
107  * until we hit natcmd
108  */
109 
110                 if (natcmd==nc) break;
111 
112                 const InetAddr *a1 = natcmd->t_addr->getAddressPtr();
113                 const InetAddr *a2 = nc->t_addr->getAddressPtr();
114 
115                 Interface *int1 = natcmd->o_iface;
116                 Interface *int2 = nc->o_iface;
117 
118                 if ((natcmd->t_addr == nc->t_addr ||
119                      (a1 && a2 && *a1 == *a2)) &&
120                     int1->getId() == int2->getId() )
121                 {
122                     natcmd->ignore_global = true;
123                     natcmd->nat_id = nc->nat_id;
124                 }
125             }
126 
127             for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
128                  i1!=pix_comp->nat_commands.end(); ++i1)
129             {
130                 NATCmd *nc = (*i1).second;
131 /* since map nat_commands is sorted by the key, we only have to scan it
132  * until we hit natcmd
133  */
134                 if (natcmd == nc) break;
135                 if (nc->ignore_nat) continue;
136 
137 /* using operator==(const Address &o1,const Address &o2) here */
138 
139                 if ( *(natcmd->o_src) == *(nc->o_src) &&
140                      *(natcmd->o_dst) == *(nc->o_dst) &&
141                      *(natcmd->o_srv) == *(nc->o_srv) &&
142                      natcmd->i_iface->getId() == nc->i_iface->getId() )
143                 {
144 /*
145  * there is another nat rule (rule #2) with the same "original"
146  * addresses and the same interface. We can drop this nat rule, but need
147  * to merge its global pool with pool of the rule #2.
148  *
149  * This nat rule could have been sharing a global pool with some other
150  * nat rule; in this case we need to find this other rule and also
151  * reassign it to the global pool of the rule #2.
152  */
153                     natcmd->ignore_nat = true;
154                     map<int,NATCmd*>::iterator i2;
155                     for (i2 = pix_comp->nat_commands.begin();
156                          i2 != pix_comp->nat_commands.end(); ++i2)
157                     {
158                         NATCmd *nc2 = i2->second;
159                         if (natcmd->nat_id == nc2->nat_id)
160                             nc2->nat_id = nc->nat_id;
161                     }
162                     natcmd->nat_id = nc->nat_id;
163                 }
164             }
165 
166             if (!natcmd->use_nat_0_0)
167             {
168                 map<int,NATCmd*>::iterator i1;
169                 for (i1 = pix_comp->nat_commands.begin();
170                      i1 != pix_comp->nat_commands.end(); ++i1)
171                 {
172                     NATCmd *nc=(*i1).second;
173 /* since map nat_commands is sorted by the key, we only have to scan it
174  * until we hit natcmd
175  */
176                     if (natcmd==nc) break;
177 
178 /* ignore nat natcmd entries for rules where we won't print 'nat'
179  * command or use 'nat 0' command since this means we won't print
180  * access-list for those rules and hense can not merge lists
181  */
182                     if (nc->ignore_nat) continue;
183                     if (nc->use_nat_0_0) continue;
184 
185                     if ( natcmd->nat_id == nc->nat_id &&
186                          natcmd->t_addr == nc->t_addr &&
187                          natcmd->i_iface->getId() == nc->i_iface->getId() )
188                     {
189 /* two nat commands with the same id, the same interface and the same
190  * translated address, but different osrc and odst. OSrc and ODst must
191  * be different, otherwise these two commands would have been merged
192  * in the previous cycle.  We can merge access lists and drop one of
193  * these nat commands. We merge ACLs by assigning them the same name.
194  */
195                         natcmd->nat_acl_name = nc->nat_acl_name;
196                         nc->ignore_nat_and_print_acl = true;
197                     }
198                 }
199             }
200 	}
201 
202     }
203     return true;
204 }
205 
206 /*
207  * The goal of this processor is to find SNAT rules that could be
208  * translated as "nat (interface) 0.0.0.0 0.0.0.0. These rules should
209  * have the same network object in OSrc that is used to define
210  * interface's network zone. The logic is simple: if network "A" is a
211  * network zone for internal interface, then only packets from this
212  * network can hit it and therefore there is no need to check source
213  * address once more in the "nat" rule.
214  *
215  * We also check for ODst and OSrv, because if the destination or the
216  * service are defined, then this optimization can not be done.
217  *
218  * This optimization can be turned off using checkbutton in the
219  * "Firewall" tab.
220  *
221  * call this processor really early, when groups have not been
222  * expanded yet.  At this point both NAT rule type and interfaces it
223  * is associated with are unknown yet. We have to partially repeat
224  * algorithms used in other rule processors to determine NAT rule type
225  * and interface.
226  *
227  * We do this optimization in two steps:
228  *
229  * 1. in this rule processor we replace object in OSrc with firewall's
230  * interface. This way we can still use other rule processors that
231  * determine rule type and assign it to interfaces, but rule won't be
232  * split onto multiple rules because of objects in OSrc. We also set
233  * boolean flags "clear_osrc" and "use_nat_0_0" on the rule.
234  *
235  * 2. further down in rule processor clearOSrc we check the flag and
236  * clear OSrc if it is set.
237  *
238  * 3. flag "use_nat_0_0" is used in printRule processor.
239  */
processNext()240 bool  NATCompiler_pix::optimizeDefaultNAT::processNext()
241 {
242 //    NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
243     NATRule *rule=getNext(); if (rule==NULL) return false;
244     tmp_queue.push_back(rule);
245 
246     RuleElementOSrc  *osrc=rule->getOSrc();
247     RuleElementOSrv  *osrv=rule->getOSrv();
248     RuleElementODst  *odst=rule->getODst();
249     RuleElementTSrc  *tsrc=rule->getTSrc();
250     RuleElementTDst  *tdst=rule->getTDst();
251 
252     if (osrc->size()>1) return true;
253     if (osrc->isAny())  return true;
254     if (!osrv->isAny()) return true;
255     if (!odst->isAny()) return true;
256 
257 /*
258  * can't use RuleElementOSrc::getFirst(bool dereference) because it
259  * returns Address::cast(o), but child element of rule element may be
260  * a group when this processor is called.
261  */
262     FWObject *o=osrc->front();
263     string osrc_id;
264     if (FWReference::cast(o)!=NULL)
265         osrc_id = FWObjectDatabase::getStringId(FWReference::cast(o)->getPointerId());
266     else
267         osrc_id = FWObjectDatabase::getStringId(o->getId());
268 
269     if ( ( !tsrc->isAny() && tdst->isAny()) ||
270          ( !osrc->isAny() && odst->isAny() && tsrc->isAny() && tdst->isAny() )
271     )
272     {
273 //  this rule type is SNAT or NONAT
274 
275         list<FWObject*> l2=compiler->fw->getByType(Interface::TYPENAME);
276         for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
277         {
278             Interface *iface=Interface::cast(*i);
279 
280             if (iface->getStr("orig_netzone_id")==osrc_id )
281             {
282                 rule->setBool("clear_osrc",true);
283                 rule->setBool("use_nat_0_0",true);
284                 osrc->clearChildren();
285                 osrc->addRef(iface);
286                 break;
287             }
288         }
289     }
290 
291     return true;
292 }
293 
processNext()294 bool  NATCompiler_pix::SuppressDuplicateNONATStatics::processNext()
295 {
296     Helper helper(compiler);
297 //    NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
298     NATRule *rule=getNext(); if (rule==NULL) return false;
299 
300     if (rule->getRuleType()== NATRule::NONAT &&
301         rule->getInt("nonat_type")==NONAT_STATIC)
302     {
303 	Address  *osrc=compiler->getFirstOSrc(rule);  assert(osrc);
304 	Address  *odst=compiler->getFirstODst(rule);  assert(odst);
305 
306         nonat_static_parameters  sp;
307         sp.iface1 = helper.findInterfaceByNetzone(osrc );
308         sp.iface2 = helper.findInterfaceByNetzone(odst );
309         sp.addr = *(odst->getAddressPtr());
310         sp.mask = *(odst->getNetmaskPtr());
311 
312         for (deque<nonat_static_parameters>::iterator i=all_nonat_statics.begin();
313              i!=all_nonat_statics.end();  ++i )
314         {
315             if ( i->iface1==sp.iface1 &&
316                  i->iface2==sp.iface2 &&
317                  i->addr==sp.addr &&
318                  i->mask==sp.mask ) return true;
319         }
320         all_nonat_statics.push_back(sp);
321     }
322 
323     tmp_queue.push_back(rule);
324     return true;
325 }
326 
~DetectOverlap()327 NATCompiler_pix::DetectOverlap::~DetectOverlap() {};
328 
checkOverlapping(const libfwbuilder::Address & addr1,const libfwbuilder::InetAddr & addr2)329 bool NATCompiler_pix::DetectOverlap::checkOverlapping(
330     const libfwbuilder::Address  &addr1,
331     const libfwbuilder::InetAddr &addr2)
332 {
333     if (AddressRange::isA(&addr1))
334     {
335         const InetAddr a1 = AddressRange::constcast(&addr1)->getRangeStart();
336         const InetAddr a2 = AddressRange::constcast(&addr1)->getRangeEnd();
337         return (addr2==a1 || addr2==a2 || (addr2>a1 && addr2<a2));
338     } else
339     {
340         return *(addr1.getAddressPtr()) == addr2 || addr1.belongs(addr2);
341     }
342 }
343 
printGlobalPoolAddress(const Address & pool)344 string NATCompiler_pix::DetectOverlap::printGlobalPoolAddress(const Address &pool)
345 {
346     if (AddressRange::isA(&pool))
347     {
348         const InetAddr a1=AddressRange::constcast(&pool)->getRangeStart();
349         const InetAddr a2=AddressRange::constcast(&pool)->getRangeEnd();
350         return a1.toString()+"-"+a2.toString();
351     } else
352     {
353         return pool.getAddressPtr()->toString() + "/" +
354             pool.getNetmaskPtr()->toString();
355     }
356 }
357 
processNext()358 bool  NATCompiler_pix::DetectGlobalPoolProblems::processNext()
359 {
360     NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
361     NATRule *rule=getNext(); if (rule==NULL) return false;
362     tmp_queue.push_back(rule);
363 
364     if (rule->getRuleType()== NATRule::SNAT )
365     {
366         NATCmd *natcmd = pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
367 
368         if (natcmd->ignore_global) return true;
369 
370         if (natcmd->type != INTERFACE)
371         {
372             if (checkOverlapping(*(natcmd->t_addr),
373                                  *(natcmd->o_iface->getAddressPtr())))
374                 compiler->abort(
375                     rule,
376                     "Global pool "
377                     + printGlobalPoolAddress(*(natcmd->t_addr))
378                     + " overlaps with interface address.");
379 
380             if (checkOverlapping(*(natcmd->t_addr),
381                                  *(natcmd->o_iface->getBroadcastAddressPtr()))
382                 ||
383                 checkOverlapping(*(natcmd->t_addr),
384                                  *(natcmd->o_iface->getAddressPtr())) )
385                 compiler->warning(
386                     rule,
387                     "Global pool "
388                     + printGlobalPoolAddress(*(natcmd->t_addr))
389                     + " overlaps with broadcast address.");
390         }
391 
392         for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
393              i1!=pix_comp->nat_commands.end(); ++i1)
394         {
395             NATCmd *nc = (*i1).second;
396 /* since map nat_commands is sorted by the key, we only have to scan it
397  * until we hit natcmd
398  */
399             if (nc->ignore_global) continue;
400             if (natcmd==nc) break;
401 
402             Interface *int1 = natcmd->o_iface;
403             Interface *int2 = nc->o_iface;
404 
405             if ( int1->getId()==int2->getId() )
406             {
407                 if ( ! fwcompiler::_find_obj_intersection(natcmd->t_addr,nc->t_addr).empty() )
408                 {
409                     compiler->abort(
410                         rule,
411                         string("Global pool overlap: ")
412                         + rule->getLabel() + " : "
413                         + printGlobalPoolAddress(*(natcmd->t_addr))
414                         + nc->rule_label + " : "
415                         + printGlobalPoolAddress(*(nc->t_addr)) );
416                 }
417             }
418 
419         }
420     }
421     return true;
422 }
423 
424 
processNext()425 bool  NATCompiler_pix::DetectOverlappingGlobalPoolsAndStaticRules::processNext()
426 {
427     NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
428     NATRule *rule=getNext(); if (rule==NULL) return false;
429     tmp_queue.push_back(rule);
430 
431     if (rule->getRuleType()== NATRule::DNAT )
432     {
433         Address  *outa=compiler->getFirstODst(rule);  assert(outa);
434         Address  *insa=compiler->getFirstTDst(rule);  assert(insa);
435 
436         for (map<int,NATCmd*>::iterator i=pix_comp->nat_commands.begin();
437              i!=pix_comp->nat_commands.end(); ++i)
438         {
439             NATCmd *natcmd=(*i).second;
440 
441             if (natcmd->ignore_global) return true;
442 
443             /* in this case natcmd->t_addr is interface. Interface creates
444              * single-address global pool, but since it has netmask,
445              * method checkOverlapping would treat it as network. I create
446              * temporary substitution Address object to avoid this .
447              *
448              * If interface is used for a global pool (SNAT rule) and
449              * for a static (DNAT rule), then this is ok even though
450              * such global pool overlaps with such static (added 10/17/03)
451              *
452              * But first I need to check if this interface has dynamic
453              * address, in which case I can not really do this check
454              * at all.
455              */
456             IPv4 addr;
457 
458             Interface *iface=Interface::cast(natcmd->t_addr);
459             if (iface!=NULL && iface->isDyn()) return true;
460 
461             if (iface!=NULL && iface->getId()==outa->getId()) return true;
462 
463             addr.setAddress(*(natcmd->t_addr->getAddressPtr()));
464             addr.setNetmask(*(natcmd->t_addr->getNetmaskPtr()));
465 
466             if (natcmd->type== INTERFACE)
467             {
468                 addr.setNetmask(InetAddr(InetAddr::getAllOnes()));
469             }
470 
471             if ( checkOverlapping(  addr, *(outa->getAddressPtr())) ||
472                  checkOverlapping( *outa, *(addr.getAddressPtr())) )
473                 compiler->abort(
474 
475                         rule,
476                         "Global pool "
477                         +printGlobalPoolAddress(addr)
478                         +" from rule "
479                         +natcmd->rule_label
480                         +" overlaps with static translation address in rule "
481                         +rule->getLabel());
482         }
483     }
484     return true;
485 }
486 
processNext()487 bool  NATCompiler_pix::DetectDuplicateNAT::processNext()
488 {
489     NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
490     NATRule *rule=getNext(); if (rule==NULL) return false;
491     tmp_queue.push_back(rule);
492 
493     if (rule->getRuleType()== NATRule::SNAT)
494     {
495         NATCmd *natcmd=pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
496 
497         if (natcmd->ignore_nat) return true;
498 
499         for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
500              i1!=pix_comp->nat_commands.end(); ++i1)
501         {
502             NATCmd *nc = (*i1).second;
503 /* since map nat_commands is sorted by the key, we only have to scan it
504  * until we hit natcmd
505  */
506             if (nc->ignore_nat) continue;
507             if (natcmd==nc) break;
508 
509             Interface *int1 = natcmd->o_iface;
510             Interface *int2 = nc->o_iface;
511 
512 //            InetAddr a1=natcmd->o_addr->getAddress();
513 //            InetAddr a2=nc->o_addr->getAddress();
514 //
515 //            InetAddr   m1=natcmd->o_addr->getInetAddr();
516 //            InetAddr   m2=nc->o_addr->getNetmask();
517 
518             if ( int1->getId()==int2->getId() &&
519                  natcmd->o_src==nc->o_src &&
520                  natcmd->o_dst==nc->o_dst &&
521                  *(natcmd->o_srv)==*(nc->o_srv)
522             )
523             {
524                 ostringstream str;
525                 str << "Duplicate NAT detected: rules "
526                     << rule->getLabel()
527                     << " and "<< nc->rule_label
528                     << " : "<< natcmd->o_src->getAddressPtr()->toString()
529                     << "/"<< natcmd->o_src->getNetmaskPtr()->toString()
530                     <<  " "
531                     <<  natcmd->o_srv->getProtocolName()
532                     << " "
533                     <<  TCPUDPService::cast(natcmd->o_srv)->getSrcRangeStart()
534                     << ":"
535                     <<  TCPUDPService::cast(natcmd->o_srv)->getSrcRangeEnd()
536                     << " "
537                     << "->"<< natcmd->o_dst->getAddressPtr()->toString()
538                     << "/"<< natcmd->o_dst->getNetmaskPtr()->toString()
539                     <<  " "
540                     <<  TCPUDPService::cast(natcmd->o_srv)->getDstRangeStart()
541                     << "/"
542                     <<  TCPUDPService::cast(natcmd->o_srv)->getDstRangeEnd();
543 
544                 compiler->abort(rule, str.str());
545         }
546     }
547 }
548 return true;
549 }
550 
processNext()551 bool  NATCompiler_pix::DetectOverlappingStatics::processNext()
552 {
553     NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
554     NATRule *rule=getNext(); if (rule==NULL) return false;
555     tmp_queue.push_back(rule);
556 
557     if (rule->getRuleType()== NATRule::DNAT )
558     {
559         StaticCmd *scmd=pix_comp->static_commands[ rule->getInt("sc_cmd") ];
560 
561         for (map<int,StaticCmd*>::iterator i1=pix_comp->static_commands.begin();
562              i1!=pix_comp->static_commands.end();  i1++ )
563         {
564 //            int        scid=i1->first;
565             StaticCmd *sc=  i1->second;
566             if (sc->ignore_scmd_and_print_acl) continue;
567             if (sc==scmd) break;
568 
569             if (Interface::isA(scmd->oaddr) && Interface::isA(sc->oaddr))
570             {
571                 if ( *(sc->osrv) == *(scmd->osrv) &&
572                      *(sc->tsrv) == *(scmd->tsrv) &&
573                      *(sc->osrc) == *(scmd->osrc) &&
574                      sc->oaddr->getId() == scmd->oaddr->getId())
575                     compiler->abort(
576 
577                             rule,
578                             "Static NAT rules overlap or are redundant : rules "+
579                             sc->rule+" and "+scmd->rule+" : "+
580                             "outside address: "+
581                             "interface "+Interface::cast(scmd->oaddr)->getLabel()+
582                             " inside address: "+
583                             scmd->iaddr->getAddressPtr()->toString()+"/"+
584                             scmd->iaddr->getNetmaskPtr()->toString());
585             } else
586             {
587                 if ( *(sc->osrv) == *(scmd->osrv) &&
588                      *(sc->tsrv) == *(scmd->tsrv) &&
589                      *(sc->osrc) == *(scmd->osrc))
590                 {
591                     const InetAddrMask *ia1 =
592                         scmd->iaddr->getInetAddrMaskObjectPtr();
593                     const InetAddrMask *ia2 =
594                         sc->iaddr->getInetAddrMaskObjectPtr();
595 
596                     const InetAddrMask *oa1 =
597                         scmd->oaddr->getInetAddrMaskObjectPtr();
598                     const InetAddrMask *oa2 =
599                         sc->oaddr->getInetAddrMaskObjectPtr();
600 
601                     if ( ! getOverlap(*(ia1), *(ia2)).empty() ||
602                          ! getOverlap(*(oa1), *(oa2)).empty() )
603                         compiler->abort(
604 
605                                 rule,
606                                 "Static NAT rules overlap or are redundant: rules "+
607                                 sc->rule+" and "+scmd->rule+" : "+
608                                 "outside address: "+
609                                 scmd->oaddr->getAddressPtr()->toString()+"/"+
610                                 scmd->oaddr->getNetmaskPtr()->toString()+
611                                 " inside address: "+
612                                 scmd->iaddr->getAddressPtr()->toString()+"/"+
613                                 scmd->iaddr->getNetmaskPtr()->toString());
614                 }
615             }
616         }
617     }
618 
619     return true;
620 }
621 
622