mirror of
https://github.com/fwbuilder/fwbuilder
synced 2026-03-21 02:37:16 +01:00
909 lines
24 KiB
C++
909 lines
24 KiB
C++
/*
|
|
|
|
Firewall Builder
|
|
|
|
Copyright (C) 2007 NetCitadel, LLC
|
|
|
|
Author: Vadim Kurland vadim@fwbuilder.org
|
|
|
|
This program is free software which we release under the GNU General Public
|
|
License. You may redistribute and/or modify this program under the terms
|
|
of that license as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
To get a copy of the GNU General Public License, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
/*
|
|
* Trying to avoid dependency on libgui (except for FWBTree, which
|
|
* will be refactored into some other common module in the future).
|
|
*/
|
|
|
|
#include "../../config.h"
|
|
|
|
#include "Importer.h"
|
|
|
|
#include <string>
|
|
#include <ios>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
#include "fwbuilder/Address.h"
|
|
#include "fwbuilder/AddressRange.h"
|
|
#include "fwbuilder/CustomService.h"
|
|
#include "fwbuilder/DNSName.h"
|
|
#include "fwbuilder/FWObject.h"
|
|
#include "fwbuilder/FWObjectDatabase.h"
|
|
#include "fwbuilder/ICMPService.h"
|
|
#include "fwbuilder/IPService.h"
|
|
#include "fwbuilder/Library.h"
|
|
#include "fwbuilder/NAT.h"
|
|
#include "fwbuilder/Network.h"
|
|
#include "fwbuilder/Policy.h"
|
|
#include "fwbuilder/Resources.h"
|
|
#include "fwbuilder/RuleElement.h"
|
|
#include "fwbuilder/TCPService.h"
|
|
#include "fwbuilder/TagService.h"
|
|
#include "fwbuilder/UDPService.h"
|
|
|
|
#include <QString>
|
|
#include <QStringList>
|
|
#include <QRegExp>
|
|
#include <QtDebug>
|
|
|
|
|
|
extern int fwbdebug;
|
|
|
|
using namespace libfwbuilder;
|
|
using namespace std;
|
|
|
|
// a functor to join list<string> into a string with separator sep
|
|
class join : public std::unary_function<std::string, void>
|
|
{
|
|
std::string *result;
|
|
std::string separator;
|
|
public:
|
|
join(std::string *res, const std::string &s)
|
|
{ result = res; separator = s; }
|
|
void operator()(std::string &s);
|
|
};
|
|
|
|
void join::operator()(string &s)
|
|
{
|
|
if (!result->empty()) *result += separator;
|
|
*result += s;
|
|
}
|
|
|
|
|
|
|
|
std::string Importer::getBadRuleColor()
|
|
{
|
|
return "#C86E6E";
|
|
}
|
|
|
|
void Importer::SaveTmpAddrToSrc()
|
|
{
|
|
src_a = tmp_a;
|
|
src_nm = tmp_nm;
|
|
}
|
|
|
|
void Importer::SaveTmpAddrToDst()
|
|
{
|
|
dst_a = tmp_a;
|
|
dst_nm = tmp_nm;
|
|
}
|
|
|
|
void Importer::SaveTmpPortToSrc()
|
|
{
|
|
src_port_op = tmp_port_op;
|
|
src_port_spec = tmp_port_spec;
|
|
}
|
|
|
|
void Importer::SaveTmpPortToDst()
|
|
{
|
|
dst_port_op = tmp_port_op;
|
|
dst_port_spec = tmp_port_spec;
|
|
}
|
|
|
|
Importer::Importer(FWObject *_lib,
|
|
const std::string &_platform,
|
|
std::istringstream &_input,
|
|
Logger *log,
|
|
const std::string &fwname) : input(_input)
|
|
{
|
|
this->fwname = fwname;
|
|
library = _lib;
|
|
fw = NULL;
|
|
error_counter = 0;
|
|
logger = log;
|
|
platform = _platform;
|
|
|
|
clear();
|
|
|
|
current_interface = NULL;
|
|
current_ruleset = NULL;
|
|
current_rule = NULL;
|
|
|
|
address_maker = new AddressObjectMaker(Library::cast(library));
|
|
service_maker = new ServiceObjectMaker(Library::cast(library));
|
|
}
|
|
|
|
void Importer::prepareForDeduplication()
|
|
{
|
|
address_maker->prepareForDeduplication(library->getRoot());
|
|
service_maker->prepareForDeduplication(library->getRoot());
|
|
}
|
|
|
|
void Importer::run()
|
|
{
|
|
// create and run parsers in derived classes
|
|
}
|
|
|
|
|
|
Importer::~Importer()
|
|
{
|
|
all_rulesets.clear();
|
|
all_interfaces.clear();
|
|
|
|
delete address_maker;
|
|
delete service_maker;
|
|
}
|
|
|
|
void Importer::clear()
|
|
{
|
|
action = "";
|
|
|
|
protocol = "";
|
|
|
|
src_a = "";
|
|
src_nm = "";
|
|
src_port_op = "";
|
|
src_port_spec = "";
|
|
|
|
dst_a = "";
|
|
dst_nm = "";
|
|
dst_port_op = "";
|
|
dst_port_spec = "";
|
|
|
|
tmp_a = "";
|
|
tmp_nm = "";
|
|
tmp_port_op = "";
|
|
tmp_port_spec = "";
|
|
tmp_port_spec_2 = "";
|
|
tmp_range_1 = "";
|
|
tmp_range_2 = "";
|
|
|
|
logging = false;
|
|
log_level = "";
|
|
log_interval = "";
|
|
|
|
established = false;
|
|
fragments = false;
|
|
|
|
icmp_spec = "";
|
|
icmp_code = "";
|
|
icmp_type = "";
|
|
|
|
time_range_name = "";
|
|
|
|
if (!tcp_flags_mask.empty()) tcp_flags_mask.clear();
|
|
if (!tcp_flags_comp.empty()) tcp_flags_comp.clear();
|
|
if (!tmp_tcp_flags_list.empty()) tmp_tcp_flags_list.clear();
|
|
|
|
}
|
|
|
|
Firewall* Importer::getFirewallObject()
|
|
{
|
|
if (fw!=NULL) return fw;
|
|
|
|
ObjectMaker maker(Library::cast(library));
|
|
FWObject *nobj = commitObject(
|
|
maker.createObject(Firewall::TYPENAME, fwname));
|
|
|
|
fw = Firewall::cast(nobj);
|
|
|
|
fw->setStr("platform", platform);
|
|
Resources::setDefaultTargetOptions(platform , fw);
|
|
|
|
return fw;
|
|
}
|
|
|
|
/*
|
|
* Creates firewall object and sets its name
|
|
*
|
|
* This assumes that configuration clase that declares host name
|
|
* comes first (true for Ciscos, but may not be true for others)
|
|
*
|
|
*/
|
|
void Importer::setHostName(const std::string &hn)
|
|
{
|
|
getFirewallObject()->setName(hn);
|
|
*logger << "Host name: " + hn + "\n";
|
|
}
|
|
|
|
void Importer::setDiscoveredVersion(const std::string &v)
|
|
{
|
|
discovered_version = v;
|
|
*logger << "Version: " + v + "\n";
|
|
}
|
|
|
|
void Importer::newInterface(const std::string &name)
|
|
{
|
|
if (all_interfaces.count(name)>0) return;
|
|
ObjectMaker maker(Library::cast(library));
|
|
FWObject *nobj = commitObject(
|
|
maker.createObject(getFirewallObject(), Interface::TYPENAME, name));
|
|
current_interface = Interface::cast(nobj);
|
|
current_interface->setUnnumbered(true);
|
|
all_interfaces[name] = current_interface;
|
|
*logger << "New interface: " + name + "\n";
|
|
}
|
|
|
|
/*
|
|
* We call this when importer for PIX or IOS encounters interface in
|
|
* state "shutdown"
|
|
*/
|
|
void Importer::ignoreCurrentInterface()
|
|
{
|
|
if (current_interface)
|
|
{
|
|
string name = current_interface->getName();
|
|
current_interface->getParent()->remove(current_interface);
|
|
all_interfaces.erase(name);
|
|
current_interface = NULL;
|
|
}
|
|
}
|
|
|
|
void Importer::addAddressObjectToInterface(Interface*intf,
|
|
const string &addr,
|
|
const string &netm)
|
|
{
|
|
intf->setUnnumbered(false);
|
|
if (addr == "dhcp") intf->setDyn(true);
|
|
else
|
|
{
|
|
string aname = getFirewallObject()->getName() + ":" + intf->getName() + ":ip";
|
|
ObjectMaker maker(Library::cast(library));
|
|
FWObject *nobj = commitObject(
|
|
maker.createObject(intf, IPv4::TYPENAME, aname));
|
|
IPv4::cast(nobj)->setAddress( InetAddr(addr) );
|
|
IPv4::cast(nobj)->setNetmask( InetAddr(netm) );
|
|
}
|
|
}
|
|
|
|
void Importer::addInterfaceAddress(const std::string &a,
|
|
const std::string &nm)
|
|
{
|
|
if (current_interface!=NULL)
|
|
{
|
|
addAddressObjectToInterface(current_interface, a, nm);
|
|
*logger << "Interface address: " + a + "/" + nm + "\n";
|
|
}
|
|
}
|
|
|
|
void Importer::addInterfaceAddress(const std::string &label,
|
|
const std::string &a,
|
|
const std::string &nm)
|
|
{
|
|
map<const string,Interface*>::iterator it;
|
|
for (it=all_interfaces.begin(); it!=all_interfaces.end(); ++it)
|
|
{
|
|
Interface *intf = it->second;
|
|
if (intf->getLabel() == label)
|
|
{
|
|
addAddressObjectToInterface(intf, a, nm);
|
|
*logger << "Interface address: " + a + "/" + nm + "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void Importer::setInterfaceComment(const std::string &descr)
|
|
{
|
|
// current_interface can be NULL if parser encountered command
|
|
// that looked like interface description but in reality was
|
|
// description of something else. For example this happens when
|
|
// it finds command "description" under "controller" in Cisco router
|
|
// configuration.
|
|
if (current_interface!=NULL)
|
|
{
|
|
current_interface->setComment(descr);
|
|
*logger << "Interface comment: " + descr + "\n";
|
|
}
|
|
}
|
|
|
|
void Importer::setInterfaceLabel(const std::string &descr)
|
|
{
|
|
if (current_interface!=NULL)
|
|
{
|
|
current_interface->setLabel(descr);
|
|
*logger << "Interface label: " + descr + "\n";
|
|
}
|
|
}
|
|
|
|
void Importer::setInterfaceParametes(const std::string &phys_intf_or_label,
|
|
const std::string &label,
|
|
const std::string &sec_level)
|
|
{
|
|
*logger << "Interface parameters: " + phys_intf_or_label +
|
|
" " + label + " " + sec_level + "\n";
|
|
|
|
if (all_interfaces.count(phys_intf_or_label))
|
|
{
|
|
// since first arg. is physical interface name, this must be pix6
|
|
// "nameif ethernet0 outside security0"
|
|
Interface *intf = all_interfaces[phys_intf_or_label];
|
|
intf->setLabel(label);
|
|
QRegExp pix6_sec_level("security(\\d+)");
|
|
if (pix6_sec_level.indexIn(sec_level.c_str()) > -1)
|
|
intf->setSecurityLevel(pix6_sec_level.cap(1).toInt());
|
|
} else
|
|
{
|
|
// since first arg is not physical interface name, it must be a label
|
|
// as in pix7 config
|
|
//
|
|
// interface Ethernet0.101
|
|
// vlan 101
|
|
// nameif outside
|
|
// security-level 0
|
|
// ip address 192.0.2.253 255.255.255.0
|
|
setInterfaceLabel(phys_intf_or_label);
|
|
}
|
|
}
|
|
|
|
void Importer::setInterfaceSecurityLevel(const std::string &seclevel)
|
|
{
|
|
if (current_interface!=NULL)
|
|
{
|
|
QString sl(seclevel.c_str());
|
|
current_interface->setSecurityLevel(sl.toInt());
|
|
}
|
|
}
|
|
|
|
void Importer::setInterfaceVlanId(const std::string &vlan_id)
|
|
{
|
|
if (current_interface!=NULL)
|
|
{
|
|
FWOptions *ifopt = (Interface::cast(current_interface))->getOptionsObject();
|
|
ifopt->setStr("type", "8021q");
|
|
ifopt->setStr("vlan_id", vlan_id);
|
|
}
|
|
}
|
|
|
|
void Importer::addRuleComment(const std::string &comm)
|
|
{
|
|
rule_comment += comm;
|
|
*logger << "Rule comment: " + comm + "\n";
|
|
}
|
|
|
|
UnidirectionalRuleSet* Importer::checkUnidirRuleSet(
|
|
const std::string &ruleset_name)
|
|
{
|
|
return all_rulesets[ruleset_name];
|
|
}
|
|
|
|
UnidirectionalRuleSet* Importer::getUnidirRuleSet(
|
|
const std::string &ruleset_name, const string &ruleset_type_name)
|
|
{
|
|
UnidirectionalRuleSet *rs = all_rulesets[ruleset_name];
|
|
if (rs==NULL)
|
|
{
|
|
// got 'ip access-group' command before the access list was defined
|
|
rs = new UnidirectionalRuleSet();
|
|
rs->name = ruleset_name;
|
|
FWObjectDatabase *dbroot = getFirewallObject()->getRoot();
|
|
rs->ruleset = RuleSet::cast(dbroot->create(ruleset_type_name));
|
|
rs->ruleset->setName(ruleset_name);
|
|
all_rulesets[ruleset_name] = rs;
|
|
// add this ruleset to the firewall temporarily
|
|
// because ruleset must belong to the tree somewhere in
|
|
// order for other objects to be added properly.
|
|
getFirewallObject()->add(rs->ruleset);
|
|
}
|
|
return rs;
|
|
}
|
|
|
|
void Importer::setInterfaceAndDirectionForRuleSet(
|
|
Interface *intf, const std::string &ruleset_name, const std::string &dir)
|
|
{
|
|
UnidirectionalRuleSet *rs = getUnidirRuleSet(ruleset_name, Policy::TYPENAME);
|
|
string intf_name = intf->getName();
|
|
if (rs->intf_dir.count(intf_name)==0) rs->intf_dir[intf_name] = dir;
|
|
else
|
|
{
|
|
// already have this interface with some direction
|
|
// compare direction, if different, switcht to "both"
|
|
if (rs->intf_dir[intf_name] != "both" && rs->intf_dir[intf_name] != dir)
|
|
rs->intf_dir[intf_name] = "both";
|
|
}
|
|
ostringstream str;
|
|
str << "Interface " << intf_name
|
|
<< " ruleset " << ruleset_name
|
|
<< " direction '" << dir << "' "
|
|
<< "\n";
|
|
*logger << str.str();
|
|
}
|
|
|
|
/*
|
|
* associate ruleset <ruleset_name> with interface <intf_name>
|
|
* and direction <dir>
|
|
*
|
|
* if <intf_name> is empty, use current_interface
|
|
*
|
|
* Note that a ruleset may be associated with multiple interfaces
|
|
* and each association can have different direction.
|
|
*/
|
|
void Importer::setInterfaceAndDirectionForRuleSet(const std::string &ruleset_name,
|
|
const std::string &intf_name,
|
|
const std::string &dir)
|
|
{
|
|
Interface *intf = NULL;
|
|
if ( ! intf_name.empty())
|
|
{
|
|
intf = all_interfaces[intf_name];
|
|
} else
|
|
{
|
|
if (current_interface) intf = current_interface;
|
|
}
|
|
|
|
if (intf == NULL)
|
|
{
|
|
// current_interface is NULL and _intf_name is empty. Not enough
|
|
// information to associate ruleset with an interface.
|
|
QString err("Can not associate rule set %1 with any interface\n");
|
|
*logger << err.arg(QString::fromUtf8(ruleset_name.c_str())).toStdString();
|
|
} else
|
|
setInterfaceAndDirectionForRuleSet(intf, ruleset_name, dir);
|
|
}
|
|
|
|
void Importer::newUnidirRuleSet(const string &ruleset_name,
|
|
const string &ruleset_type)
|
|
{
|
|
current_ruleset = getUnidirRuleSet(ruleset_name, ruleset_type); // creates if new
|
|
current_ruleset->created_from_line_number = getCurrentLineNumber();
|
|
*logger << "Ruleset: " + ruleset_name + "\n";
|
|
}
|
|
|
|
/*
|
|
* Grammar must ensure the call to setDefaultAction() happens
|
|
* after the call to newUnidirRuleSet()
|
|
*
|
|
*/
|
|
void Importer::setDefaultAction(const std::string &iptables_action_name)
|
|
{
|
|
string default_action_str = "Deny";
|
|
if (iptables_action_name == "ACCEPT")
|
|
{
|
|
current_ruleset->default_action = PolicyRule::Accept;
|
|
current_ruleset->default_action_line_number = getCurrentLineNumber();
|
|
default_action_str = "Accept";
|
|
} else current_ruleset->default_action = PolicyRule::Deny;
|
|
|
|
*logger << "Default action: " + default_action_str + "\n";
|
|
}
|
|
|
|
void Importer::newPolicyRule()
|
|
{
|
|
if (fwbdebug) qDebug() << "Importer::newPolicyRule()";
|
|
|
|
FWObjectDatabase *dbroot = getFirewallObject()->getRoot();
|
|
FWObject *nobj = dbroot->create(PolicyRule::TYPENAME);
|
|
current_rule = Rule::cast(nobj);
|
|
|
|
// check if all child objects were populated properly
|
|
FWOptions *ropt = current_rule->getOptionsObject();
|
|
assert(ropt!=NULL);
|
|
ropt->setBool("stateless", true);
|
|
}
|
|
|
|
void Importer::newNATRule()
|
|
{
|
|
if (fwbdebug) qDebug() << "Importer::newNATRule()";
|
|
|
|
FWObjectDatabase *dbroot = getFirewallObject()->getRoot();
|
|
FWObject *nobj = dbroot->create(NATRule::TYPENAME);
|
|
current_rule = Rule::cast(nobj);
|
|
|
|
if (fwbdebug) qDebug() << "current_rule=" << current_rule;
|
|
}
|
|
|
|
void Importer::pushRule()
|
|
{
|
|
assert(current_ruleset!=NULL);
|
|
assert(current_rule!=NULL);
|
|
// populate all elements of the rule
|
|
|
|
//qDebug() << QString("Adding rule from line %1").arg(getCurrentLineNumber())
|
|
// << "current_rule=" << current_rule;
|
|
|
|
PolicyRule *rule = PolicyRule::cast(current_rule);
|
|
|
|
FWOptions *ropt = current_rule->getOptionsObject();
|
|
assert(ropt!=NULL);
|
|
|
|
if (action=="permit")
|
|
{
|
|
rule->setAction(PolicyRule::Accept);
|
|
ropt->setBool("stateless", false);
|
|
}
|
|
|
|
if (action=="deny")
|
|
{
|
|
rule->setAction(PolicyRule::Deny);
|
|
ropt->setBool("stateless", true);
|
|
}
|
|
|
|
rule->setDirection(PolicyRule::Both);
|
|
|
|
addSrc();
|
|
addDst();
|
|
addSrv();
|
|
|
|
addLogging();
|
|
|
|
// then add it to the current ruleset
|
|
current_ruleset->ruleset->add(current_rule);
|
|
|
|
addStandardImportComment(current_rule, QString::fromUtf8(rule_comment.c_str()));
|
|
|
|
current_rule = NULL;
|
|
rule_comment = "";
|
|
|
|
clear();
|
|
}
|
|
|
|
void Importer::setSrcSelf()
|
|
{
|
|
src_a = "self";
|
|
}
|
|
|
|
void Importer::setDstSelf()
|
|
{
|
|
dst_a = "self";
|
|
}
|
|
|
|
FWObject* Importer::makeSrcObj()
|
|
{
|
|
if (src_a == "self")
|
|
{
|
|
return getFirewallObject();
|
|
}
|
|
|
|
if ( (src_a=="" && src_nm=="") ||
|
|
(src_a==InetAddr::getAny().toString() &&
|
|
src_nm==InetAddr::getAny().toString()))
|
|
return NULL; // this is 'any'
|
|
|
|
if (src_nm=="") src_nm = InetAddr::getAllOnes().toString();
|
|
|
|
ObjectSignature sig;
|
|
sig.type_name = Address::TYPENAME;
|
|
sig.setAddress(src_a.c_str());
|
|
sig.setNetmask(src_nm.c_str(), address_maker->getInvertedNetmasks());
|
|
|
|
return commitObject(address_maker->createObject(sig));
|
|
}
|
|
|
|
FWObject* Importer::makeDstObj()
|
|
{
|
|
if (dst_a == "self")
|
|
{
|
|
return getFirewallObject();
|
|
}
|
|
|
|
if ( (dst_a=="" && dst_nm=="") ||
|
|
(dst_a==InetAddr::getAny().toString() &&
|
|
dst_nm==InetAddr::getAny().toString()))
|
|
return NULL; // this is 'any'
|
|
|
|
if (dst_nm=="") dst_nm=InetAddr::getAllOnes().toString();
|
|
|
|
ObjectSignature sig;
|
|
sig.type_name = Address::TYPENAME;
|
|
sig.setAddress(dst_a.c_str());
|
|
sig.setNetmask(dst_nm.c_str(), address_maker->getInvertedNetmasks());
|
|
|
|
return commitObject(address_maker->createObject(sig));
|
|
}
|
|
|
|
FWObject* Importer::makeSrvObj()
|
|
{
|
|
if (protocol=="") return NULL; // this is 'any'
|
|
FWObject *s;
|
|
if (protocol=="icmp")
|
|
{
|
|
ObjectSignature sig;
|
|
sig.type_name = ICMPService::TYPENAME;
|
|
if ( ! icmp_spec.empty())
|
|
{
|
|
sig.setIcmpFromName(icmp_spec.c_str());
|
|
} else
|
|
{
|
|
sig.setIcmpType(icmp_type.c_str());
|
|
sig.setIcmpCode(icmp_code.c_str());
|
|
}
|
|
s = service_maker->createObject(sig);
|
|
} else
|
|
{
|
|
if (protocol=="tcp")
|
|
{
|
|
s = createTCPService();
|
|
} else
|
|
{
|
|
if (protocol=="udp")
|
|
{
|
|
s = createUDPService();
|
|
} else
|
|
{
|
|
ObjectSignature sig;
|
|
sig.type_name = IPService::TYPENAME;
|
|
sig.setProtocol(protocol.c_str());
|
|
sig.fragments = fragments;
|
|
s = service_maker->createObject(sig);
|
|
}
|
|
}
|
|
}
|
|
// if create*Service returns NULL, this is 'any'
|
|
return commitObject(s);
|
|
}
|
|
|
|
void Importer::addSrc()
|
|
{
|
|
PolicyRule *rule = PolicyRule::cast(current_rule);
|
|
RuleElementSrc* src = rule->getSrc();
|
|
assert(src!=NULL);
|
|
FWObject *s = makeSrcObj();
|
|
if (s) src->addRef( s );
|
|
}
|
|
|
|
void Importer::addDst()
|
|
{
|
|
PolicyRule *rule = PolicyRule::cast(current_rule);
|
|
RuleElementDst* dst = rule->getDst();
|
|
assert(dst!=NULL);
|
|
FWObject *s = makeDstObj();
|
|
if (s) dst->addRef( s );
|
|
}
|
|
|
|
void Importer::addSrv()
|
|
{
|
|
PolicyRule *rule = PolicyRule::cast(current_rule);
|
|
RuleElementSrv* srv = rule->getSrv();
|
|
assert(srv!=NULL);
|
|
FWObject *s = makeSrvObj();
|
|
if (s) srv->addRef( s );
|
|
}
|
|
|
|
void Importer::addOSrc()
|
|
{
|
|
NATRule *rule = NATRule::cast(current_rule);
|
|
RuleElementOSrc* src = rule->getOSrc();
|
|
assert(src!=NULL);
|
|
FWObject *s = makeSrcObj();
|
|
if (s) src->addRef( s );
|
|
}
|
|
|
|
void Importer::addODst()
|
|
{
|
|
NATRule *rule = NATRule::cast(current_rule);
|
|
RuleElementODst* dst = rule->getODst();
|
|
assert(dst!=NULL);
|
|
FWObject *s = makeDstObj();
|
|
if (s) dst->addRef( s );
|
|
}
|
|
|
|
void Importer::addOSrv()
|
|
{
|
|
NATRule *rule = NATRule::cast(current_rule);
|
|
RuleElementOSrv* srv = rule->getOSrv();
|
|
assert(srv!=NULL);
|
|
FWObject *s= makeSrvObj();
|
|
if (s) srv->addRef( s );
|
|
}
|
|
|
|
void Importer::addLogging()
|
|
{
|
|
PolicyRule *rule = PolicyRule::cast(current_rule);
|
|
rule->setLogging(logging);
|
|
// log_level
|
|
// log_interval
|
|
}
|
|
|
|
Firewall* Importer::finalize()
|
|
{
|
|
return fw;
|
|
}
|
|
|
|
FWObject* Importer::createTCPService(const QString &)
|
|
{
|
|
// Default implementation
|
|
return NULL;
|
|
}
|
|
|
|
FWObject* Importer::createUDPService(const QString &)
|
|
{
|
|
// Default implementation
|
|
return NULL;
|
|
}
|
|
|
|
FWObject* Importer::createGroupOfInterfaces(
|
|
const std::string &ruleset_name, std::list<std::string> &interfaces)
|
|
{
|
|
std::string name = "intf-" + ruleset_name;
|
|
// by including ruleset name (==acl name) into the signature we
|
|
// force import to create separate interface group for each access list
|
|
// even if interface set is the same as for some other access list.
|
|
// This decision is rather arbitrary but it feels less confusing
|
|
// compared to the case when interface groups cretaed from different
|
|
// access lists are merged. If they are merged, the name refers to one
|
|
// access list which looks weird in the GUI since rules may have been
|
|
// imported from another access list.
|
|
std::string sig = ruleset_name + "_";
|
|
std::for_each(interfaces.begin(), interfaces.end(), join(&sig, "_"));
|
|
|
|
if (fwbdebug)
|
|
qDebug() << QString("Interface group with name '%1', sig '%2'")
|
|
.arg(name.c_str()).arg(sig.c_str());
|
|
|
|
if (all_objects.count(sig)!=0) return all_objects[sig];
|
|
|
|
ObjectMaker maker(Library::cast(library));
|
|
ObjectGroup *og = ObjectGroup::cast(
|
|
commitObject(
|
|
maker.createObject(ObjectGroup::TYPENAME, name)));
|
|
|
|
for (std::list<std::string>::iterator j=interfaces.begin(); j!=interfaces.end(); ++j)
|
|
{
|
|
Interface *intf = all_interfaces[*j];
|
|
og->addRef(intf);
|
|
}
|
|
all_objects[sig] = og;
|
|
return og;
|
|
}
|
|
|
|
/**
|
|
* set color of the current rule (use red) and add comment
|
|
* to indicate that the rule could not be properly parsed
|
|
*/
|
|
void Importer::markCurrentRuleBad(const std::string &comment)
|
|
{
|
|
FWOptions *ropt = current_rule->getOptionsObject();
|
|
assert(ropt!=NULL);
|
|
ropt->setStr("color", getBadRuleColor());
|
|
if (!rule_comment.empty()) rule_comment += "\n";
|
|
rule_comment += comment;
|
|
}
|
|
|
|
void Importer::reportError(const std::string &comment)
|
|
{
|
|
reportError(QString::fromUtf8(comment.c_str()));
|
|
}
|
|
|
|
void Importer::reportError(const QString &comment)
|
|
{
|
|
error_counter++;
|
|
QString err = QObject::tr("Parser error: Line %1: %2\n")
|
|
.arg(getCurrentLineNumber()).arg(comment);
|
|
*logger << err.toUtf8().constData();
|
|
if (current_rule != NULL) markCurrentRuleBad(comment.toUtf8().constData());
|
|
}
|
|
|
|
int Importer::countRules()
|
|
{
|
|
int n = 0;
|
|
std::map<const string, UnidirectionalRuleSet*>::iterator it;
|
|
for (it=all_rulesets.begin(); it!=all_rulesets.end(); ++it)
|
|
{
|
|
// rs_index is a string composed of the table name and chain name
|
|
// like "filter / FORWARD" or "mangle / PREROUTING"
|
|
// This string is created in IPTImporter::getUnidirRuleSet()
|
|
string rs_index = it->first;
|
|
UnidirectionalRuleSet* rs = it->second;
|
|
n += rs->ruleset->getRuleSetSize();
|
|
}
|
|
return n;
|
|
}
|
|
|
|
int Importer::countInterfaces()
|
|
{
|
|
if (haveFirewallObject())
|
|
{
|
|
Firewall *fw = Firewall::cast(getFirewallObject());
|
|
list<FWObject*> all_interface_objects = fw->getByType(Interface::TYPENAME);
|
|
return all_interface_objects.size();
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
QString Importer::noFirewallErrorMessage()
|
|
{
|
|
return QObject::tr(
|
|
"Could not find enough information in the data file "
|
|
"to create firewall object."
|
|
"\n\n"
|
|
);
|
|
}
|
|
|
|
QString Importer::noRulesErrorMessage()
|
|
{
|
|
return QObject::tr(
|
|
"Could not find enough information in the data file "
|
|
"to create any firewall rules."
|
|
"\n\n"
|
|
);
|
|
}
|
|
|
|
QString Importer::noInterfacesErrorMessage()
|
|
{
|
|
return QObject::tr(
|
|
"Could not find enough information in the data file "
|
|
"to create firewall interface objects."
|
|
"\n\n"
|
|
);
|
|
}
|
|
|
|
/*
|
|
* This is a common error message shown by the importer when it fails
|
|
* to create firewall object. Keeping it in the base class since it is
|
|
* used in the finalize() function of all importer classes.
|
|
*/
|
|
QString Importer::commonFailureErrorMessage()
|
|
{
|
|
return QObject::tr(
|
|
"Please check that the "
|
|
"file you are trying to import is in one of supported "
|
|
"formats. Currently fwbuilder can only import "
|
|
"iptables configuration saved with "
|
|
"'iptables-restore' command and Cisco routers (IOS) "
|
|
"configurations saved with 'show run' command. Import "
|
|
"of cisco ASA (PIX) configuration is not supported "
|
|
"at this time");
|
|
}
|
|
|
|
void Importer::addMessageToLog(const std::string &msg)
|
|
{
|
|
*logger << msg + "\n";
|
|
}
|
|
|
|
void Importer::addStandardImportComment(FWObject *obj,
|
|
const QString &additional_comment)
|
|
{
|
|
if (obj == NULL) return;
|
|
|
|
// what if this object has been found in a read-only library?
|
|
if (obj->isReadOnly()) return;
|
|
|
|
// this function may get called again if object is being reused
|
|
if ( obj->getBool(".import-commited")) return;
|
|
|
|
QStringList comment;
|
|
|
|
if ( ! obj->getComment().empty())
|
|
comment << QString::fromUtf8(obj->getComment().c_str());
|
|
|
|
if ( ! additional_comment.isEmpty()) comment << additional_comment;
|
|
|
|
QString file_and_line("Created during import of %1 line %2");
|
|
comment << file_and_line
|
|
.arg(QString::fromUtf8(input_file_name.c_str()))
|
|
.arg(getCurrentLineNumber());
|
|
|
|
obj->setComment(comment.join("\n").toUtf8().constData());
|
|
obj->setBool(".import-commited", true);
|
|
}
|
|
|
|
FWObject* Importer::commitObject(FWObject *obj)
|
|
{
|
|
// what if this object has been found in a read-only library?
|
|
if (obj->isReadOnly()) return obj;
|
|
if (obj) addStandardImportComment(obj, "");
|
|
return obj;
|
|
}
|
|
|