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