1 /*
2
3 Firewall Builder
4
5 Copyright (C) 2007 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 /*
25 * Trying to avoid dependency on libgui (except for FWBTree, which
26 * will be refactored into some other common module in the future).
27 */
28
29 #include "../../config.h"
30
31 #include "Importer.h"
32
33 #include <string>
34 #include <ios>
35 #include <iostream>
36 #include <algorithm>
37 #include <memory>
38
39 #include "interfaceProperties.h"
40 #include "interfacePropertiesObjectFactory.h"
41
42 #include "fwbuilder/Address.h"
43 #include "fwbuilder/AddressRange.h"
44 #include "fwbuilder/CustomService.h"
45 #include "fwbuilder/DNSName.h"
46 #include "fwbuilder/FWObject.h"
47 #include "fwbuilder/FWObjectDatabase.h"
48 #include "fwbuilder/ICMPService.h"
49 #include "fwbuilder/IPService.h"
50 #include "fwbuilder/Library.h"
51 #include "fwbuilder/NAT.h"
52 #include "fwbuilder/Network.h"
53 #include "fwbuilder/Policy.h"
54 #include "fwbuilder/Resources.h"
55 #include "fwbuilder/RuleElement.h"
56 #include "fwbuilder/TCPService.h"
57 #include "fwbuilder/TagService.h"
58 #include "fwbuilder/UDPService.h"
59
60 #include <QString>
61 #include <QStringList>
62 #include <QRegExp>
63 #include <QtDebug>
64
65
66 extern int fwbdebug;
67
68 using namespace libfwbuilder;
69 using namespace std;
70
71 // a functor to join list<string> into a string with separator sep
72 class join : public std::unary_function<std::string, void>
73 {
74 std::string *result;
75 std::string separator;
76 public:
join(std::string * res,const std::string & s)77 join(std::string *res, const std::string &s)
78 { result = res; separator = s; }
79 void operator()(std::string &s);
80 };
81
operator ()(string & s)82 void join::operator()(string &s)
83 {
84 if (!result->empty()) *result += separator;
85 *result += s;
86 }
87
88
89
getBadRuleColor()90 std::string Importer::getBadRuleColor()
91 {
92 return "#C86E6E";
93 }
94
SaveTmpAddrToSrc()95 void Importer::SaveTmpAddrToSrc()
96 {
97 src_a = tmp_a;
98 src_nm = tmp_nm;
99 }
100
SaveTmpAddrToDst()101 void Importer::SaveTmpAddrToDst()
102 {
103 dst_a = tmp_a;
104 dst_nm = tmp_nm;
105 }
106
SaveTmpPortToSrc()107 void Importer::SaveTmpPortToSrc()
108 {
109 src_port_op = tmp_port_op;
110 src_port_spec = tmp_port_spec;
111 }
112
SaveTmpPortToDst()113 void Importer::SaveTmpPortToDst()
114 {
115 dst_port_op = tmp_port_op;
116 dst_port_spec = tmp_port_spec;
117 }
118
Importer(FWObject * _lib,const std::string & _platform,std::istringstream & _input,Logger * log,const std::string & fwname)119 Importer::Importer(FWObject *_lib,
120 const std::string &_platform,
121 std::istringstream &_input,
122 Logger *log,
123 const std::string &fwname) : input(_input)
124 {
125 this->fwname = fwname;
126 library = _lib;
127 fw = NULL;
128 error_counter = 0;
129 logger = log;
130 platform = _platform;
131
132 current_interface = NULL;
133 current_ruleset = NULL;
134 current_rule = NULL;
135
136 error_tracker = new ObjectMakerErrorTracker();
137
138 address_maker = new AddressObjectMaker(Library::cast(library), error_tracker);
139 service_maker = new ServiceObjectMaker(Library::cast(library), error_tracker);
140
141 clear();
142
143 }
144
prepareForDeduplication()145 void Importer::prepareForDeduplication()
146 {
147 address_maker->prepareForDeduplication(library->getRoot());
148 service_maker->prepareForDeduplication(library->getRoot());
149 }
150
run()151 void Importer::run()
152 {
153 // create and run parsers in derived classes
154 }
155
156
~Importer()157 Importer::~Importer()
158 {
159 all_rulesets.clear();
160 all_interfaces.clear();
161
162 delete address_maker;
163 delete service_maker;
164
165 delete error_tracker;
166 }
167
clear()168 void Importer::clear()
169 {
170 last_comment.clear();
171
172 action = "";
173
174 protocol = "";
175
176 src_a = "";
177 src_nm = "";
178 src_port_op = "";
179 src_port_spec = "";
180
181 dst_a = "";
182 dst_nm = "";
183 dst_port_op = "";
184 dst_port_spec = "";
185
186 tmp_a = "";
187 tmp_nm = "";
188 tmp_port_op = "";
189 tmp_port_spec = "";
190 tmp_port_spec_2 = "";
191 tmp_range_1 = "";
192 tmp_range_2 = "";
193
194 logging = false;
195 log_level = "";
196 log_interval = "";
197
198 established = false;
199 fragments = false;
200
201 icmp_spec = "";
202 icmp_code = "";
203 icmp_type = "";
204
205 time_range_name = "";
206
207 if (!tcp_flags_mask.empty()) tcp_flags_mask.clear();
208 if (!tcp_flags_comp.empty()) tcp_flags_comp.clear();
209 if (!tmp_tcp_flags_list.empty()) tmp_tcp_flags_list.clear();
210
211 error_tracker->clear();
212 }
213
getFirewallObject()214 Firewall* Importer::getFirewallObject()
215 {
216 if (fw!=NULL) return fw;
217
218 ObjectMaker maker(Library::cast(library), error_tracker);
219 FWObject *nobj = commitObject(
220 maker.createObject(Firewall::TYPENAME, fwname));
221
222 fw = Firewall::cast(nobj);
223
224 fw->setStr("platform", platform);
225 Resources::setDefaultTargetOptions(platform , fw);
226
227 return fw;
228 }
229
230 /*
231 * Creates firewall object and sets its name
232 *
233 * This assumes that configuration clase that declares host name
234 * comes first (true for Ciscos, but may not be true for others)
235 *
236 */
setHostName(const std::string & hn)237 void Importer::setHostName(const std::string &hn)
238 {
239 getFirewallObject()->setName(hn);
240 addMessageToLog("Host name: " + hn);
241 }
242
setDiscoveredVersion(const std::string & v)243 void Importer::setDiscoveredVersion(const std::string &v)
244 {
245 discovered_version = v;
246 addMessageToLog("Version: " + v);
247 }
248
setDiscoveredPlatform(const std::string & v)249 void Importer::setDiscoveredPlatform(const std::string &v)
250 {
251 discovered_platform = v;
252 addMessageToLog("Platform: " + v);
253 }
254
newInterface(const std::string & name)255 Interface* Importer::newInterface(const std::string &name)
256 {
257 if (all_interfaces.count(name)>0) return all_interfaces[name];
258 ObjectMaker maker(Library::cast(library), error_tracker);
259 FWObject *nobj = commitObject(
260 maker.createObject(getFirewallObject(), Interface::TYPENAME, name));
261 current_interface = Interface::cast(nobj);
262 current_interface->setUnnumbered(true);
263 all_interfaces[name] = current_interface;
264 addMessageToLog(QObject::tr("New interface: %1").arg(name.c_str()));
265 return current_interface;
266 }
267
268 /*
269 * We call this when importer for PIX or IOS encounters interface in
270 * state "shutdown"
271 */
ignoreCurrentInterface()272 void Importer::ignoreCurrentInterface()
273 {
274 if (current_interface)
275 {
276 string name = current_interface->getName();
277 current_interface->getParent()->remove(current_interface);
278 all_interfaces.erase(name);
279 current_interface = NULL;
280 }
281 }
282
addAddressObjectToInterface(Interface * intf,const string & addr,const string & netm)283 void Importer::addAddressObjectToInterface(Interface*intf,
284 const string &addr,
285 const string &netm)
286 {
287 intf->setUnnumbered(false);
288 if (addr == "dhcp") intf->setDyn(true);
289 else
290 {
291 string aname = getFirewallObject()->getName() + ":" + intf->getName() + ":ip";
292 ObjectMaker maker(Library::cast(library), error_tracker);
293 FWObject *nobj = commitObject(
294 maker.createObject(intf, IPv4::TYPENAME, aname));
295 IPv4::cast(nobj)->setAddress( InetAddr(addr) );
296 IPv4::cast(nobj)->setNetmask( InetAddr(netm) );
297 }
298 }
299
addInterfaceAddress(const std::string & a,const std::string & nm)300 void Importer::addInterfaceAddress(const std::string &a,
301 const std::string &nm)
302 {
303 if (current_interface!=NULL)
304 {
305 addAddressObjectToInterface(current_interface, a, nm);
306 addMessageToLog("Interface address: " + a + "/" + nm);
307 }
308 }
309
addInterfaceAddress(const std::string & label,const std::string & a,const std::string & nm)310 void Importer::addInterfaceAddress(const std::string &label,
311 const std::string &a,
312 const std::string &nm)
313 {
314 map<const string,Interface*>::iterator it;
315 for (it=all_interfaces.begin(); it!=all_interfaces.end(); ++it)
316 {
317 Interface *intf = it->second;
318 if (intf->getLabel() == label)
319 {
320 addAddressObjectToInterface(intf, a, nm);
321 addMessageToLog("Interface address: " + a + "/" + nm);
322 }
323 }
324 }
325
setInterfaceComment(const std::string & descr)326 void Importer::setInterfaceComment(const std::string &descr)
327 {
328 // current_interface can be NULL if parser encountered command
329 // that looked like interface description but in reality was
330 // description of something else. For example this happens when
331 // it finds command "description" under "controller" in Cisco router
332 // configuration.
333 if (current_interface!=NULL)
334 {
335 current_interface->setComment(descr);
336 addMessageToLog("Interface comment: " + descr);
337 }
338 }
339
setInterfaceLabel(const std::string & descr)340 void Importer::setInterfaceLabel(const std::string &descr)
341 {
342 if (current_interface!=NULL)
343 {
344 current_interface->setLabel(descr);
345 addMessageToLog("Interface label: " + descr);
346 }
347 }
348
setInterfaceParametes(const std::string & phys_intf_or_label,const std::string & label,const std::string & sec_level)349 void Importer::setInterfaceParametes(const std::string &phys_intf_or_label,
350 const std::string &label,
351 const std::string &sec_level)
352 {
353 addMessageToLog("Interface parameters: " + phys_intf_or_label +
354 " " + label + " " + sec_level);
355
356 if (all_interfaces.count(phys_intf_or_label))
357 {
358 // since first arg. is physical interface name, this must be pix6
359 // "nameif ethernet0 outside security0"
360 Interface *intf = all_interfaces[phys_intf_or_label];
361 intf->setLabel(label);
362 QRegExp pix6_sec_level("security(\\d+)");
363 if (pix6_sec_level.indexIn(sec_level.c_str()) > -1)
364 intf->setSecurityLevel(pix6_sec_level.cap(1).toInt());
365 } else
366 {
367 // since first arg is not physical interface name, it must be a label
368 // as in pix7 config
369 //
370 // interface Ethernet0.101
371 // vlan 101
372 // nameif outside
373 // security-level 0
374 // ip address 192.0.2.253 255.255.255.0
375 setInterfaceLabel(phys_intf_or_label);
376 }
377 }
378
setInterfaceSecurityLevel(const std::string & seclevel)379 void Importer::setInterfaceSecurityLevel(const std::string &seclevel)
380 {
381 if (current_interface!=NULL)
382 {
383 QString sl(seclevel.c_str());
384 current_interface->setSecurityLevel(sl.toInt());
385 }
386 }
387
setInterfaceVlanId(const std::string & vlan_id)388 void Importer::setInterfaceVlanId(const std::string &vlan_id)
389 {
390 if (current_interface!=NULL)
391 {
392 FWOptions *ifopt = (Interface::cast(current_interface))->getOptionsObject();
393 ifopt->setStr("type", "8021q");
394 ifopt->setStr("vlan_id", vlan_id);
395 }
396 }
397
addRuleComment(const std::string & comm)398 void Importer::addRuleComment(const std::string &comm)
399 {
400 rule_comment += comm;
401 addMessageToLog("Rule comment: " + comm);
402 }
403
checkUnidirRuleSet(const std::string & ruleset_name)404 UnidirectionalRuleSet* Importer::checkUnidirRuleSet(
405 const std::string &ruleset_name)
406 {
407 return all_rulesets[ruleset_name];
408 }
409
getUnidirRuleSet(const std::string & ruleset_name,const string & ruleset_type_name)410 UnidirectionalRuleSet* Importer::getUnidirRuleSet(
411 const std::string &ruleset_name, const string &ruleset_type_name)
412 {
413 UnidirectionalRuleSet *rs = all_rulesets[ruleset_name];
414 if (rs==NULL)
415 {
416 // got 'ip access-group' command before the access list was defined
417 rs = new UnidirectionalRuleSet();
418 rs->name = ruleset_name;
419 FWObjectDatabase *dbroot = getFirewallObject()->getRoot();
420 rs->ruleset = RuleSet::cast(dbroot->create(ruleset_type_name));
421 rs->ruleset->setName(ruleset_name);
422 all_rulesets[ruleset_name] = rs;
423 // add this ruleset to the firewall temporarily
424 // because ruleset must belong to the tree somewhere in
425 // order for other objects to be added properly.
426 getFirewallObject()->add(rs->ruleset);
427 }
428 return rs;
429 }
430
setInterfaceAndDirectionForRuleSet(Interface * intf,const std::string & ruleset_name,const std::string & dir)431 void Importer::setInterfaceAndDirectionForRuleSet(
432 Interface *intf, const std::string &ruleset_name, const std::string &dir)
433 {
434 UnidirectionalRuleSet *rs = getUnidirRuleSet(ruleset_name, Policy::TYPENAME);
435 string intf_name = intf->getName();
436 if (rs->intf_dir.count(intf_name)==0) rs->intf_dir[intf_name] = dir;
437 else
438 {
439 // already have this interface with some direction
440 // compare direction, if different, switcht to "both"
441 if (rs->intf_dir[intf_name] != "both" && rs->intf_dir[intf_name] != dir)
442 rs->intf_dir[intf_name] = "both";
443 }
444 QString l("Interface %1 ruleset %2 direction '%3'");
445 addMessageToLog(
446 l.arg(intf_name.c_str()).arg(ruleset_name.c_str()).arg(dir.c_str()));
447 }
448
449 /*
450 * associate ruleset <ruleset_name> with interface <intf_name>
451 * and direction <dir>
452 *
453 * if <intf_name> is empty, use current_interface
454 *
455 * Note that a ruleset may be associated with multiple interfaces
456 * and each association can have different direction.
457 */
setInterfaceAndDirectionForRuleSet(const std::string & ruleset_name,const std::string & intf_name,const std::string & dir)458 void Importer::setInterfaceAndDirectionForRuleSet(const std::string &ruleset_name,
459 const std::string &intf_name,
460 const std::string &dir)
461 {
462 Interface *intf = NULL;
463 if ( ! intf_name.empty())
464 {
465 intf = all_interfaces[intf_name];
466 } else
467 {
468 if (current_interface) intf = current_interface;
469 }
470
471 if (intf == NULL)
472 {
473 // current_interface is NULL and _intf_name is empty. Not enough
474 // information to associate ruleset with an interface.
475 QString err("Can not associate rule set %1 with any interface\n");
476 addMessageToLog(err.arg(QString::fromUtf8(ruleset_name.c_str())));
477 } else
478 setInterfaceAndDirectionForRuleSet(intf, ruleset_name, dir);
479 }
480
newUnidirRuleSet(const string & ruleset_name,const string & ruleset_type)481 void Importer::newUnidirRuleSet(const string &ruleset_name,
482 const string &ruleset_type)
483 {
484 current_ruleset = getUnidirRuleSet(ruleset_name, ruleset_type); // creates if new
485 current_ruleset->created_from_line_number = getCurrentLineNumber();
486 //*logger << "Ruleset: " + ruleset_name + "\n";
487 }
488
489 /*
490 * Grammar must ensure the call to setDefaultAction() happens
491 * after the call to newUnidirRuleSet()
492 *
493 */
setDefaultAction(const std::string & iptables_action_name)494 void Importer::setDefaultAction(const std::string &iptables_action_name)
495 {
496 string default_action_str = "Deny";
497 if (iptables_action_name == "ACCEPT")
498 {
499 current_ruleset->default_action = PolicyRule::Accept;
500 current_ruleset->default_action_line_number = getCurrentLineNumber();
501 default_action_str = "Accept";
502 } else current_ruleset->default_action = PolicyRule::Deny;
503
504 addMessageToLog("Default action: " + default_action_str);
505 }
506
newPolicyRule()507 void Importer::newPolicyRule()
508 {
509 if (fwbdebug) qDebug() << "Importer::newPolicyRule()";
510
511 FWObjectDatabase *dbroot = getFirewallObject()->getRoot();
512 FWObject *nobj = dbroot->create(PolicyRule::TYPENAME);
513 current_rule = Rule::cast(nobj);
514
515 // check if all child objects were populated properly
516 FWOptions *ropt = current_rule->getOptionsObject();
517 assert(ropt!=NULL);
518 ropt->setBool("stateless", true);
519 }
520
newNATRule()521 void Importer::newNATRule()
522 {
523 if (fwbdebug) qDebug() << "Importer::newNATRule()";
524
525 FWObjectDatabase *dbroot = getFirewallObject()->getRoot();
526 FWObject *nobj = dbroot->create(NATRule::TYPENAME);
527 current_rule = Rule::cast(nobj);
528
529 if (fwbdebug) qDebug() << "current_rule=" << current_rule;
530 }
531
pushRule()532 void Importer::pushRule()
533 {
534 assert(current_ruleset!=NULL);
535 assert(current_rule!=NULL);
536 // populate all elements of the rule
537
538 PolicyRule *rule = PolicyRule::cast(current_rule);
539
540 FWOptions *ropt = current_rule->getOptionsObject();
541 assert(ropt!=NULL);
542
543 if (action=="permit")
544 {
545 rule->setAction(PolicyRule::Accept);
546 ropt->setBool("stateless", false);
547 }
548
549 if (action=="deny")
550 {
551 rule->setAction(PolicyRule::Deny);
552 ropt->setBool("stateless", true);
553 }
554
555 rule->setDirection(PolicyRule::Both);
556
557 addSrc();
558 addDst();
559 addSrv();
560
561 addLogging();
562
563 // then add it to the current ruleset
564 current_ruleset->ruleset->add(current_rule);
565
566 if (error_tracker->hasWarnings())
567 {
568 QStringList warn = error_tracker->getWarnings();
569 // parser errors and warnings are added to the log by
570 // PFCfgParser::reportError() and PFCfgParser::reportWarning()
571 // so we dont need to add them again here
572 foreach(QString w, warn)
573 {
574 if (!w.startsWith("Parser warning:")) addMessageToLog("Warning: " + w);
575 }
576 markCurrentRuleBad();
577 }
578
579 if (error_tracker->hasErrors())
580 {
581 QStringList err = error_tracker->getErrors();
582 foreach(QString e, err)
583 {
584 if (!e.startsWith("Parser error:")) addMessageToLog("Error: " + e);
585 }
586 markCurrentRuleBad();
587 }
588
589 addStandardImportComment(
590 current_rule, QString::fromUtf8(rule_comment.c_str()));
591
592 current_rule = NULL;
593 rule_comment = "";
594
595 clear();
596 }
597
setSrcSelf()598 void Importer::setSrcSelf()
599 {
600 src_a = "self";
601 }
602
setDstSelf()603 void Importer::setDstSelf()
604 {
605 dst_a = "self";
606 }
607
makeAddressObj(const std::string addr,const std::string netm)608 FWObject* Importer::makeAddressObj(const std::string addr, const std::string netm)
609 {
610 if (addr == "self")
611 {
612 return getFirewallObject();
613 }
614
615 if ( (addr=="" && netm=="") ||
616 (addr==InetAddr::getAny().toString() &&
617 netm==InetAddr::getAny().toString()))
618 return NULL; // this is 'any'
619
620 ObjectSignature sig(error_tracker);
621 sig.type_name = Address::TYPENAME;
622 sig.setAddress(addr.c_str());
623 if (netm=="")
624 sig.setNetmask(InetAddr::getAllOnes().toString().c_str(),
625 address_maker->getInvertedNetmasks());
626 else
627 sig.setNetmask(netm.c_str(), address_maker->getInvertedNetmasks());
628
629 return commitObject(address_maker->createObject(sig));
630 }
631
makeSrcObj()632 FWObject* Importer::makeSrcObj()
633 {
634 return makeAddressObj(src_a, src_nm);
635 }
636
makeDstObj()637 FWObject* Importer::makeDstObj()
638 {
639 return makeAddressObj(dst_a, dst_nm);
640 }
641
makeSrvObj()642 FWObject* Importer::makeSrvObj()
643 {
644 if (protocol=="") return NULL; // this is 'any'
645 FWObject *s;
646 if (protocol=="icmp")
647 {
648 ObjectSignature sig(error_tracker);
649 sig.type_name = ICMPService::TYPENAME;
650 if ( ! icmp_spec.empty())
651 {
652 sig.setIcmpFromName(icmp_spec.c_str());
653 } else
654 {
655 sig.setIcmpType(icmp_type.c_str());
656 sig.setIcmpCode(icmp_code.c_str());
657 }
658 s = service_maker->createObject(sig);
659 } else
660 {
661 if (protocol=="tcp")
662 {
663 s = createTCPService();
664 } else
665 {
666 if (protocol=="udp")
667 {
668 s = createUDPService();
669 } else
670 {
671 ObjectSignature sig(error_tracker);
672 sig.type_name = IPService::TYPENAME;
673 sig.setProtocol(protocol.c_str());
674 sig.fragments = fragments;
675 s = service_maker->createObject(sig);
676 }
677 }
678 }
679 // if create*Service returns NULL, this is 'any'
680 return commitObject(s);
681 }
682
addSrc()683 void Importer::addSrc()
684 {
685 PolicyRule *rule = PolicyRule::cast(current_rule);
686 RuleElementSrc* src = rule->getSrc();
687 assert(src!=NULL);
688 FWObject *s = makeSrcObj();
689 if (s) src->addRef( s );
690 }
691
addDst()692 void Importer::addDst()
693 {
694 PolicyRule *rule = PolicyRule::cast(current_rule);
695 RuleElementDst* dst = rule->getDst();
696 assert(dst!=NULL);
697 FWObject *s = makeDstObj();
698 if (s) dst->addRef( s );
699 }
700
addSrv()701 void Importer::addSrv()
702 {
703 PolicyRule *rule = PolicyRule::cast(current_rule);
704 RuleElementSrv* srv = rule->getSrv();
705 assert(srv!=NULL);
706 FWObject *s = makeSrvObj();
707 if (s) srv->addRef( s );
708 }
709
addOSrc()710 void Importer::addOSrc()
711 {
712 NATRule *rule = NATRule::cast(current_rule);
713 RuleElementOSrc* src = rule->getOSrc();
714 assert(src!=NULL);
715 FWObject *s = makeSrcObj();
716 if (s) src->addRef( s );
717 }
718
addODst()719 void Importer::addODst()
720 {
721 NATRule *rule = NATRule::cast(current_rule);
722 RuleElementODst* dst = rule->getODst();
723 assert(dst!=NULL);
724 FWObject *s = makeDstObj();
725 if (s) dst->addRef( s );
726 }
727
addOSrv()728 void Importer::addOSrv()
729 {
730 NATRule *rule = NATRule::cast(current_rule);
731 RuleElementOSrv* srv = rule->getOSrv();
732 assert(srv!=NULL);
733 FWObject *s= makeSrvObj();
734 if (s) srv->addRef( s );
735 }
736
addLogging()737 void Importer::addLogging()
738 {
739 PolicyRule *rule = PolicyRule::cast(current_rule);
740 rule->setLogging(logging);
741 // log_level
742 // log_interval
743 }
744
finalize()745 Firewall* Importer::finalize()
746 {
747 return fw;
748 }
749
createTCPService(const QString &)750 FWObject* Importer::createTCPService(const QString &)
751 {
752 // Default implementation
753 return NULL;
754 }
755
createUDPService(const QString &)756 FWObject* Importer::createUDPService(const QString &)
757 {
758 // Default implementation
759 return NULL;
760 }
761
createGroupOfInterfaces(const std::string & ruleset_name,std::list<std::string> & interfaces)762 FWObject* Importer::createGroupOfInterfaces(
763 const std::string &ruleset_name, std::list<std::string> &interfaces)
764 {
765 std::string name = "intf-" + ruleset_name;
766 // by including ruleset name (==acl name) into the signature we
767 // force import to create separate interface group for each access list
768 // even if interface set is the same as for some other access list.
769 // This decision is rather arbitrary but it feels less confusing
770 // compared to the case when interface groups cretaed from different
771 // access lists are merged. If they are merged, the name refers to one
772 // access list which looks weird in the GUI since rules may have been
773 // imported from another access list.
774 std::string sig = ruleset_name + "_";
775 std::for_each(interfaces.begin(), interfaces.end(), join(&sig, "_"));
776
777 if (fwbdebug)
778 qDebug() << QString("Interface group with name '%1', sig '%2'")
779 .arg(name.c_str()).arg(sig.c_str());
780
781 if (all_objects.count(sig)!=0) return all_objects[sig];
782
783 ObjectMaker maker(Library::cast(library), error_tracker);
784 ObjectGroup *og = ObjectGroup::cast(
785 commitObject(
786 maker.createObject(ObjectGroup::TYPENAME, name)));
787
788 for (std::list<std::string>::iterator j=interfaces.begin(); j!=interfaces.end(); ++j)
789 {
790 Interface *intf = all_interfaces[*j];
791 og->addRef(intf);
792 }
793 all_objects[sig] = og;
794 return og;
795 }
796
797 /**
798 * set color of the current rule (use red) and add comment
799 * to indicate that the rule could not be properly parsed
800 */
markCurrentRuleBad()801 void Importer::markCurrentRuleBad()
802 {
803 FWOptions *ropt = current_rule->getOptionsObject();
804 assert(ropt!=NULL);
805 ropt->setStr("color", getBadRuleColor());
806
807 QStringList comment;
808 if ( ! current_rule->getComment().empty())
809 comment.append(QString::fromUtf8(current_rule->getComment().c_str()));
810
811 foreach(QString err, error_tracker->getWarnings())
812 comment.append(err);
813
814 foreach(QString err, error_tracker->getErrors())
815 comment.append(err);
816
817 current_rule->setComment(comment.join("\n").toUtf8().constData());
818 }
819
reportError(const std::string & comment)820 void Importer::reportError(const std::string &comment)
821 {
822 reportError(QString::fromUtf8(comment.c_str()));
823 }
824
reportError(const QString & comment)825 void Importer::reportError(const QString &comment)
826 {
827 error_counter++;
828 QString err = QObject::tr("Error: %1").arg(comment);
829 addMessageToLog(err);
830 error_tracker->registerError(err);
831 }
832
countRules()833 int Importer::countRules()
834 {
835 int n = 0;
836 std::map<const string, UnidirectionalRuleSet*>::iterator it;
837 for (it=all_rulesets.begin(); it!=all_rulesets.end(); ++it)
838 {
839 // rs_index is a string composed of the table name and chain name
840 // like "filter / FORWARD" or "mangle / PREROUTING"
841 // This string is created in IPTImporter::getUnidirRuleSet()
842 string rs_index = it->first;
843 UnidirectionalRuleSet* rs = it->second;
844 if (rs->ruleset)
845 n += rs->ruleset->getRuleSetSize();
846 }
847 return n;
848 }
849
countInterfaces()850 int Importer::countInterfaces()
851 {
852 if (haveFirewallObject())
853 {
854 Firewall *fw = Firewall::cast(getFirewallObject());
855 list<FWObject*> all_interface_objects = fw->getByType(Interface::TYPENAME);
856 return all_interface_objects.size();
857 } else
858 return 0;
859 }
860
noFirewallErrorMessage()861 QString Importer::noFirewallErrorMessage()
862 {
863 return QObject::tr(
864 "Could not find enough information in the data file "
865 "to create firewall object."
866 "\n\n"
867 );
868 }
869
noRulesErrorMessage()870 QString Importer::noRulesErrorMessage()
871 {
872 return QObject::tr(
873 "Could not find enough information in the data file "
874 "to create any firewall rules."
875 "\n\n"
876 );
877 }
878
noInterfacesErrorMessage()879 QString Importer::noInterfacesErrorMessage()
880 {
881 return QObject::tr(
882 "Could not find enough information in the data file "
883 "to create firewall interface objects."
884 "\n\n"
885 );
886 }
887
888 /*
889 * This is a common error message shown by the importer when it fails
890 * to create firewall object. Keeping it in the base class since it is
891 * used in the finalize() function of all importer classes.
892 */
commonFailureErrorMessage()893 QString Importer::commonFailureErrorMessage()
894 {
895 return QObject::tr(
896 "Please check that the "
897 "file you are trying to import is in one of supported "
898 "formats. Currently fwbuilder can only import "
899 "iptables configuration saved with "
900 "'iptables-restore' command, Cisco routers (IOS), "
901 "Cisco ASA, FWSM and PIX configurations saved with "
902 "'show run' command and PF configuration from a pf.conf file."
903 );
904 }
905
addMessageToLog(const std::string & msg)906 void Importer::addMessageToLog(const std::string &msg)
907 {
908 addMessageToLog(QString::fromUtf8(msg.c_str()));
909 }
910
addMessageToLog(const QString & msg)911 void Importer::addMessageToLog(const QString &msg)
912 {
913 if (getCurrentLineNumber() >= 0)
914 {
915 QString log_line("%1: %2\n");
916 *logger << log_line.arg(getCurrentLineNumber()).arg(msg).toUtf8().constData();
917 } else
918 {
919 *logger << msg.toUtf8().constData();
920 }
921 }
922
923 /**
924 * This function adds "standard" comment to the object, plus text
925 * passed as @additional_comment argument. If the object already has
926 * some comment, it is preserved and new text is appended to it. If
927 * flag add_standard_comments is false, then comment referring to the
928 * line number in the original file is not added, but
929 * @additional_comment is added anyway. Note that we also add comments
930 * to rules in case of errors but those are not suppressed by the flag
931 * add_standard_comments
932 */
addStandardImportComment(FWObject * obj,const QString & additional_comment)933 void Importer::addStandardImportComment(FWObject *obj,
934 const QString &additional_comment)
935 {
936 if (obj == NULL) return;
937
938 // what if this object has been found in a read-only library?
939 if (obj->isReadOnly()) return;
940
941 // this function may get called again if object is being reused
942 if ( obj->getBool(".import-commited")) return;
943
944 QStringList comment;
945
946 if ( ! obj->getComment().empty())
947 comment << QString::fromUtf8(obj->getComment().c_str());
948
949 if ( ! additional_comment.isEmpty()) comment << additional_comment;
950
951 if (add_standard_comments)
952 {
953 QString file_and_line("Created during import of %1 line %2");
954 comment << file_and_line
955 .arg(QString::fromUtf8(input_file_name.c_str()))
956 .arg(getCurrentLineNumber());
957 }
958
959 obj->setComment(comment.join("\n").toUtf8().constData());
960 obj->setBool(".import-commited", true);
961 }
962
commitObject(FWObject * obj)963 FWObject* Importer::commitObject(FWObject *obj)
964 {
965 // what if this object has been found in a read-only library?
966 if (obj->isReadOnly()) return obj;
967 if (obj) addStandardImportComment(obj, "");
968 return obj;
969 }
970
971 /*
972 * Rearrange vlan interfaces. Importer creates all interfaces as
973 * children of the firewall. Vlan interfaces should become
974 * subinterfaces of the corresponding physical interfaces.
975 */
rearrangeVlanInterfaces()976 void Importer::rearrangeVlanInterfaces()
977 {
978 std::auto_ptr<interfaceProperties> int_prop(
979 interfacePropertiesObjectFactory::getInterfacePropertiesObject(
980 getFirewallObject()));
981
982 list<FWObject*> all_interface_objects =
983 getFirewallObject()->getByTypeDeep(Interface::TYPENAME);
984 list<FWObject*> vlans;
985 list<FWObject*>::iterator it;
986 for (it=all_interface_objects.begin(); it!=all_interface_objects.end(); ++it)
987 {
988 Interface *intf = Interface::cast(*it);
989 FWOptions *ifopt = intf->getOptionsObject();
990
991 if (int_prop->looksLikeVlanInterface(intf->getName().c_str()) &&
992 ifopt->getStr("type")=="8021q")
993 {
994 qDebug() << "Found vlan interface" << intf->getName().c_str();
995 vlans.push_back(intf);
996 }
997 }
998
999 for (it=vlans.begin(); it!=vlans.end(); ++it)
1000 {
1001 Interface *vlan_intf = Interface::cast(*it);
1002
1003 qDebug() << "VLAN " << vlan_intf->getName().c_str();
1004
1005 QString base_name;
1006 int vlan_id;
1007 int_prop->parseVlan(vlan_intf->getName().c_str(), &base_name, &vlan_id);
1008
1009 qDebug() << "base name" << base_name;
1010
1011 if ( ! base_name.isEmpty())
1012 {
1013 getFirewallObject()->remove(vlan_intf, false); // do not delete
1014
1015 list<FWObject*>::iterator it2;
1016 for (it2=all_interface_objects.begin(); it2!=all_interface_objects.end(); ++it2)
1017 {
1018 if (base_name == (*it2)->getName().c_str())
1019 {
1020 (*it2)->add(vlan_intf, false);
1021 break;
1022 }
1023 }
1024 }
1025 }
1026
1027 }
1028
registerBrokenObject(FWObject * obj,const QString & err)1029 void Importer::registerBrokenObject(FWObject *obj, const QString &err)
1030 {
1031 broken_objects[obj] = err;
1032 }
1033
isObjectBroken(FWObject * obj)1034 bool Importer::isObjectBroken(FWObject *obj)
1035 {
1036 return broken_objects.count(obj) != 0;
1037 }
1038
getBrokenObjectError(FWObject * obj)1039 QString Importer::getBrokenObjectError(FWObject *obj)
1040 {
1041 return broken_objects[obj];
1042 }
1043
1044