1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-24 12:17:26 +01:00
fwbuilder/src/iptlib/AutomaticRules_ipt.cpp
2011-03-12 15:52:09 -08:00

477 lines
19 KiB
C++

/*
Firewall Builder
Copyright (C) 2011 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
*/
#include "AutomaticRules_ipt.h"
#include "fwbuilder/Address.h"
#include "fwbuilder/FWException.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Library.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/Rule.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/StateSyncClusterGroup.h"
#include "fwbuilder/UDPService.h"
#include "fwbuilder/FailoverClusterGroup.h"
#include "fwbuilder/IPService.h"
#include <QString>
using namespace fwcompiler;
using namespace libfwbuilder;
using namespace std;
PolicyRule* AutomaticRules_ipt::addMgmtRule(
Address* src, Address* dst, Service* service, Interface* iface,
const PolicyRule::Direction direction,
const PolicyRule::Action action,
const string &label,
bool related)
{
PolicyRule *rule = AutomaticRules::addMgmtRule(src, dst, service,
iface, direction, action,
label);
FWOptions *ruleopt = rule->getOptionsObject(); assert(ruleopt!=NULL);
if (related)
{
ruleopt->setBool("stateless", false);
ruleopt->setBool("accept_established", true);
} else
{
ruleopt->setBool("stateless", true);
}
ruleopt->setBool("firewall_is_part_of_any_and_networks", true);
return rule;
}
void AutomaticRules_ipt::addConntrackRule()
{
if (ruleset == NULL) return;
FWOptions* options = fw->getOptionsObject();
string conntrack_iface_name = options->getStr("state_sync_interface");
if (conntrack_iface_name.empty())
{
/* CONNTRACK not active, nothing left to do */
return;
}
string conntrack_group_id = options->getStr("state_sync_group_id");
StateSyncClusterGroup *state_sync_group =
StateSyncClusterGroup::cast(
ruleset->getRoot()->findInIndex(
FWObjectDatabase::getIntId(conntrack_group_id)));
Resources *os_res = Resources::os_res[fw->getStr("host_OS")];
assert(os_res != NULL);
string default_address =
os_res->getResourceStr("/FWBuilderResources/Target/protocols/conntrack/default_address");
string default_port =
os_res->getResourceStr("/FWBuilderResources/Target/protocols/conntrack/default_port");
bool ucast = state_sync_group->getOptionsObject()->getBool("conntrack_unicast");
string addr = state_sync_group->getOptionsObject()->getStr("conntrack_address");
if (addr.empty()) addr = default_address;
try
{
InetAddr(addr);
} catch (FWException &ex)
{
try
{
InetAddr(AF_INET6, addr);
} catch (FWException &ex)
{
throw FWException(string("Invalid IP address for conntrack: ") + addr);
}
}
string port = state_sync_group->getOptionsObject()->getStr("conntrack_port");
if (port.empty()) port = default_port;
/* Add CONNTRACK-Address to database */
Address *conntrack_dst = Address::cast(ruleset->getRoot()->create(IPv4::TYPENAME));
conntrack_dst->setName("CONNTRACK-Address");
conntrack_dst->setAddress(InetAddr(addr));
// Why the whole multicast adress range ?
//conntrack_dst->setNetmask(InetAddr("240.0.0.0"));
conntrack_dst->setComment("CONNTRACK Multicast Address");
persistent_objects->add(conntrack_dst);
UDPService *conntrack_srv = UDPService::cast(ruleset->getRoot()->create(UDPService::TYPENAME));
conntrack_srv->setName("CONNTRACK-UDP");
conntrack_srv->setDstRangeStart(atoi(port.c_str()));
conntrack_srv->setDstRangeEnd(atoi(port.c_str()));
conntrack_srv->setComment("CONNTRACK UDP port");
persistent_objects->add(conntrack_srv);
/* Find conntrack interface */
Interface* conntrack_iface = Interface::cast(fw->findObjectByName(Interface::TYPENAME, conntrack_iface_name));
if (conntrack_iface == NULL)
{
throw FWException(
"Unable to get CONNTRACK interface ("+ conntrack_iface_name +")");
}
/* Add automatic rules for CONNTRACK */
if (ucast)
{
Interface *fw_iface = NULL;
list<Interface*> other_interfaces;
for (FWObjectTypedChildIterator it =
state_sync_group->findByType(FWObjectReference::TYPENAME);
it != it.end(); ++it)
{
Interface *iface =
Interface::cast(FWObjectReference::getObject(*it));
assert(iface);
if (iface->isChildOf(fw))
{
fw_iface = iface;
} else
{
other_interfaces.push_back(iface);
}
}
for (list<Interface*>::iterator it=other_interfaces.begin(); it!=other_interfaces.end(); ++it)
{
Interface *other_iface = *it;
addMgmtRule(other_iface,
fw,
conntrack_srv,
fw_iface,
PolicyRule::Inbound,
PolicyRule::Accept,
"CONNTRACK");
addMgmtRule(fw,
other_iface,
conntrack_srv,
fw_iface,
PolicyRule::Outbound,
PolicyRule::Accept,
"CONNTRACK");
}
} else
{
addMgmtRule(NULL,
conntrack_dst,
conntrack_srv,
conntrack_iface,
PolicyRule::Inbound,
PolicyRule::Accept,
"CONNTRACK");
addMgmtRule(fw,
conntrack_dst,
conntrack_srv,
conntrack_iface,
PolicyRule::Outbound,
PolicyRule::Accept,
"CONNTRACK");
}
}
void AutomaticRules_ipt::addFailoverRules()
{
if (ruleset == NULL) return;
Resources *os_res = Resources::os_res[fw->getStr("host_OS")];
assert(os_res != NULL);
string default_heartbeat_port =
os_res->getResourceStr(
"/FWBuilderResources/Target/protocols/heartbeat/default_port");
string default_heartbeat_address =
os_res->getResourceStr(
"/FWBuilderResources/Target/protocols/heartbeat/default_address");
string default_openais_port =
os_res->getResourceStr(
"/FWBuilderResources/Target/protocols/openais/default_port");
string default_openais_address =
os_res->getResourceStr(
"/FWBuilderResources/Target/protocols/openais/default_address");
FWObjectTypedChildIterator interfaces = fw->findByType(Interface::TYPENAME);
for (; interfaces != interfaces.end(); ++interfaces)
{
Interface *iface = Interface::cast(*interfaces);
/*
We add copies of cluster interface objects to fw objects
so each interface appears twice, the original interface
of the firewall, plus a copy of the cluster
interface. To deduplicate will use only copies of
cluster interfaces because these include VRRP interfaces.
*/
if (iface->isFailoverInterface() &&
iface->getOptionsObject()->getBool("cluster_interface"))
{
FWObject *failover_group =
iface->getFirstByType(FailoverClusterGroup::TYPENAME);
PolicyRule *rule = NULL;
string fw_iface_id = iface->getOptionsObject()->getStr("base_interface_id");
Interface *fw_iface =
Interface::cast(
ruleset->getRoot()->findInIndex(FWObjectDatabase::getIntId(fw_iface_id)));
if (fw_iface == NULL)
{
throw FWException(
QString("Can not find interface of the firewall "
"for the cluster failover group %1. ")
.arg(failover_group->getName().c_str()).toStdString());
}
if (failover_group->getStr("type") == "vrrp")
{
/* Add VRRP-Address to database */
Address *vrrp_dst = Address::cast(
ruleset->getRoot()->create(IPv4::TYPENAME));
vrrp_dst->setName("VRRP-Address");
vrrp_dst->setAddress(InetAddr("224.0.0.18"));
vrrp_dst->setNetmask(InetAddr(InetAddr::getAllOnes()));
vrrp_dst->setComment("VRRP Multicast Address");
persistent_objects->add(vrrp_dst);
bool use_ipsec_ah = false;
FWOptions *failover_opts =
FailoverClusterGroup::cast(failover_group)->getOptionsObject();
if (failover_opts)
{
use_ipsec_ah = failover_opts->getBool("vrrp_over_ipsec_ah");
}
/* Add VRRP-Service to database */
IPService* vrrp_srv = IPService::cast(
ruleset->getRoot()->create(IPService::TYPENAME));
vrrp_srv->setComment("VRRP service");
vrrp_srv->setProtocolNumber(112);
persistent_objects->add(vrrp_srv);
/*
* Add AH-Service to database.
* According to RFC 2338 section 5.3.6.3, VRRP can use
* IPsec AH.
*/
IPService* ah_srv = IPService::cast(
ruleset->getRoot()->create(IPService::TYPENAME));
ah_srv->setComment("IPSEC-AH");
ah_srv->setProtocolNumber(51);
persistent_objects->add(ah_srv);
for (FWObjectTypedChildIterator it =
failover_group->findByType(FWObjectReference::TYPENAME);
it != it.end(); ++it)
{
Interface *other_iface =
Interface::cast(FWObjectReference::getObject(*it));
assert(other_iface);
if (other_iface->getId() == fw_iface->getId()) continue;
// if interface is dynamic, we can't use it in the rule
// (because it belongs to another machine, not the fw
// we compile for so we can't use script). NULL means "any"
// in the call to addMgmtRule()
if (other_iface->isDyn()) other_iface = NULL;
if (!use_ipsec_ah)
{
addMgmtRule(other_iface, vrrp_dst, vrrp_srv, iface,
PolicyRule::Inbound, PolicyRule::Accept,
"VRRP");
} else
{
addMgmtRule(other_iface, vrrp_dst, ah_srv, iface,
PolicyRule::Inbound, PolicyRule::Accept,
"VRRP (with IPSEC-AH)");
}
}
// outbound rule does not use other_interface and
// should be created outside the loop to avoid
// duplicates. Duplicates happen when cluster has 3 or
// more members.
if (!use_ipsec_ah)
{
addMgmtRule(fw, vrrp_dst, vrrp_srv, iface,
PolicyRule::Outbound, PolicyRule::Accept,
"VRRP");
} else
{
addMgmtRule(fw, vrrp_dst, ah_srv, iface,
PolicyRule::Outbound, PolicyRule::Accept,
"VRRP (with IPSEC-AH)");
}
}
if (failover_group->getStr("type") == "heartbeat")
{
/*
* Note that iface is a copy of the cluster inetrface.
* Find interface of the member firewall fw that corresponds
* to the cluster interface iface
*/
bool ucast = FailoverClusterGroup::cast(failover_group)->
getOptionsObject()->getBool("heartbeat_unicast");
string addr = FailoverClusterGroup::cast(failover_group)->
getOptionsObject()->getStr("heartbeat_address");
if (addr.empty()) addr = default_heartbeat_address;
string port = FailoverClusterGroup::cast(failover_group)->
getOptionsObject()->getStr("heartbeat_port");
if (port.empty()) port = default_heartbeat_port;
UDPService *heartbeat_srv = UDPService::cast(
ruleset->getRoot()->create(UDPService::TYPENAME));
/* Add heartbeat-Address to database */
Address *heartbeat_dst = Address::cast(ruleset->getRoot()->create(
IPv4::TYPENAME));
heartbeat_dst->setName("HEARTBEAT-Address");
heartbeat_dst->setAddress(InetAddr(addr));
heartbeat_dst->setNetmask(InetAddr(InetAddr::getAllOnes()));
heartbeat_dst->setComment("HEARTBEAT Multicast Address");
persistent_objects->add(heartbeat_dst);
heartbeat_srv->setName("HEARTBEAT-UDP");
heartbeat_srv->setDstRangeStart(atoi(port.c_str()));
heartbeat_srv->setDstRangeEnd(atoi(port.c_str()));
heartbeat_srv->setComment("HEARTBEAT UDP port");
persistent_objects->add(heartbeat_srv);
// Heartbeat can use either multicast or unicast
for (FWObjectTypedChildIterator it =
failover_group->findByType(FWObjectReference::TYPENAME);
it != it.end(); ++it)
{
Interface *other_iface =
Interface::cast(FWObjectReference::getObject(*it));
assert(other_iface);
if (other_iface->getId() == fw_iface->getId()) continue;
// if interface is dynamic, we can't use it in the rule
// (because it belongs to another machine, not the fw
// we compile for so we can't use script). NULL means "any"
// in the call to addMgmtRule()
if (other_iface->isDyn()) other_iface = NULL;
if (ucast)
{
addMgmtRule(other_iface, fw, heartbeat_srv, fw_iface,
PolicyRule::Inbound, PolicyRule::Accept,
"heartbeat");
addMgmtRule(fw, other_iface, heartbeat_srv, fw_iface,
PolicyRule::Outbound, PolicyRule::Accept,
"heartbeat");
}
else
{
addMgmtRule(other_iface, heartbeat_dst, heartbeat_srv, fw_iface,
PolicyRule::Inbound, PolicyRule::Accept,
"heartbeat");
addMgmtRule(fw, heartbeat_dst, heartbeat_srv, fw_iface,
PolicyRule::Outbound, PolicyRule::Accept,
"heartbeat");
}
}
}
if (failover_group->getStr("type") == "openais")
{
string addr = FailoverClusterGroup::cast(failover_group)->
getOptionsObject()->getStr("openais_address");
if (addr.empty()) addr = default_openais_address;
string port = FailoverClusterGroup::cast(failover_group)->
getOptionsObject()->getStr("openais_port");
if (port.empty()) port = default_openais_port;
/* Add OPENAIS-Address to database */
Address *openais_dst = Address::cast(ruleset->getRoot()->create(
IPv4::TYPENAME));
openais_dst->setName("OPENAIS-Address");
openais_dst->setAddress(InetAddr(addr));
openais_dst->setNetmask(InetAddr(InetAddr::getAllOnes()));
openais_dst->setComment("OPENAIS Multicast Address");
persistent_objects->add(openais_dst);
UDPService *openais_srv = UDPService::cast(
ruleset->getRoot()->create(UDPService::TYPENAME));
openais_srv->setName("OPENAIS-UDP");
openais_srv->setDstRangeStart(atoi(port.c_str()));
openais_srv->setDstRangeEnd(atoi(port.c_str()));
openais_srv->setComment("OPENAIS UDP port");
persistent_objects->add(openais_srv);
for (FWObjectTypedChildIterator it =
failover_group->findByType(FWObjectReference::TYPENAME);
it != it.end(); ++it)
{
Interface *other_iface =
Interface::cast(FWObjectReference::getObject(*it));
assert(other_iface);
if (other_iface->getId() == fw_iface->getId()) continue;
// if interface is dynamic, we can't use it in the rule
// (because it belongs to another machine, not the fw
// we compile for so we can't use script). NULL means "any"
// in the call to addMgmtRule()
if (other_iface->isDyn()) other_iface = NULL;
addMgmtRule(other_iface, openais_dst, openais_srv, iface,
PolicyRule::Inbound, PolicyRule::Accept,
"openais");
addMgmtRule(fw, openais_dst, openais_srv, iface,
PolicyRule::Outbound, PolicyRule::Accept,
"openais");
}
}
if (rule)
{
FWOptions *ruleopt = rule->getOptionsObject();
assert(ruleopt!=NULL);
ruleopt->setInt("firewall_is_part_of_any_and_networks", 1);
}
}
}
}