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