mirror of
https://github.com/fwbuilder/fwbuilder
synced 2026-03-19 01:37:17 +01:00
when user opens the firewall or any of its children objects in the editor. This includes any rule set, interface or any other child object. Also moved function Interface::getParentHost() from class Interface to class Host as static FWObject* Host::getParentHost(FWObject *o). Its behavior is now more logical, it returns non-NULL pointer only if an object actually has a parent that is host, firewall or cluster. Old function Interface::getParentHost() returned non-NULL pointer even when object was not in the proper position in the tree. Now this function can be used to get parent host/firewall/cluster for any child object rather than only interface. I had to fix bunch of problems in unit tests that got uncovered because new function behaves in a more strict way (returns NULL when there is no parent of correct type).
556 lines
15 KiB
C++
556 lines
15 KiB
C++
/*
|
|
* cluster members dialog implementation
|
|
*
|
|
* Copyright (c) 2008 secunet Security Networks AG
|
|
* Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger@swiss-it.ch>
|
|
* Copyright (c) 2008 Reto Buerki <buerki@swiss-it.ch>
|
|
*
|
|
* This work is dual-licensed under:
|
|
*
|
|
* o The terms of the GNU General Public License as published by the Free
|
|
* Software Foundation, either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* o The terms of NetCitadel End User License Agreement
|
|
*/
|
|
|
|
#include "clusterMembersDialog.h"
|
|
#include "global.h"
|
|
#include "utils_no_qt.h"
|
|
|
|
#include "FWWindow.h"
|
|
#include "Help.h"
|
|
#include "FWCmdChange.h"
|
|
|
|
#include "fwbuilder/FWObjectDatabase.h"
|
|
#include "fwbuilder/Cluster.h"
|
|
#include "fwbuilder/ClusterGroup.h"
|
|
#include "fwbuilder/Interface.h"
|
|
#include "fwbuilder/Resources.h"
|
|
|
|
#include <memory>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <qdebug.h>
|
|
#include <qpixmapcache.h>
|
|
|
|
#include <QHeaderView>
|
|
#include <QUndoStack>
|
|
|
|
|
|
using namespace std;
|
|
using namespace libfwbuilder;
|
|
|
|
typedef std::list<libfwbuilder::Firewall *> t_fwList;
|
|
|
|
clusterMembersDialog::clusterMembersDialog(QWidget *parent, FWObject *o)
|
|
: QDialog(parent), table_update(false)
|
|
{
|
|
m_dialog = new Ui::clusterMembersDialog_q;
|
|
m_dialog->setupUi(this);
|
|
setWindowModality(Qt::WindowModal);
|
|
|
|
// assign clustergroup object
|
|
obj = o;
|
|
host_os = obj->getParent()->getStr("host_OS").c_str();
|
|
platform = obj->getParent()->getStr("platform").c_str();
|
|
|
|
// if empty, retry with parent of parent (interface level)
|
|
if (host_os.isEmpty())
|
|
{
|
|
FWObject *parent = NULL;
|
|
parent = obj->getParent();
|
|
if (parent == NULL)
|
|
{
|
|
throw FWException("clusterMembersDialog: parent is NULL!");
|
|
}
|
|
parent = parent->getParent();
|
|
if (parent == NULL)
|
|
{
|
|
throw FWException("clusterMembersDialog: parent is NULL!");
|
|
}
|
|
host_os = parent->getStr("host_OS").c_str();
|
|
platform = parent->getStr("platform").c_str();
|
|
}
|
|
|
|
string type = obj->getStr("type");
|
|
enable_master_column = Resources::os_res[host_os.toStdString()]->getResourceBool(
|
|
"/FWBuilderResources/Target/protocols/" + type + "/needs_master");
|
|
if (!enable_master_column) m_dialog->fwSelectedTable->hideColumn(2);
|
|
|
|
// prepare lists of firewalls (selected, available)
|
|
getSelectedMembers();
|
|
getPossibleMembers();
|
|
|
|
// init views
|
|
updateAvailableTree();
|
|
updateSelectedTable();
|
|
}
|
|
|
|
clusterMembersDialog::~clusterMembersDialog()
|
|
{
|
|
// clear member lists
|
|
for (t_memberList::iterator it = available.begin();
|
|
it != available.end(); it++)
|
|
{
|
|
delete *it;
|
|
}
|
|
available.clear();
|
|
|
|
for (t_memberList::iterator it = selected.begin();
|
|
it != selected.end(); it++)
|
|
{
|
|
delete *it;
|
|
}
|
|
selected.clear();
|
|
|
|
delete m_dialog;
|
|
}
|
|
|
|
void clusterMembersDialog::getSelectedMembers()
|
|
{
|
|
// read in master interface id
|
|
std::string master_iface = obj->getStr("master_iface");
|
|
|
|
for (FWObjectTypedChildIterator it =
|
|
obj->findByType(FWObjectReference::TYPENAME);
|
|
it != it.end(); ++it)
|
|
{
|
|
|
|
// get fw and interface pointer from interface reference
|
|
Interface *iface = NULL;
|
|
iface = Interface::cast(FWReference::cast((*it))->getPointer());
|
|
assert(iface != NULL);
|
|
Firewall *fw = Firewall::cast(Host::getParentHost(iface));
|
|
//Firewall *fw = Firewall::cast(iface->getParentHost());
|
|
|
|
// determine master
|
|
std::string iface_id = FWObjectDatabase::getStringId(iface->getId());
|
|
bool master = false;
|
|
if (iface_id == master_iface)
|
|
{
|
|
master = true;
|
|
}
|
|
// create ClusterMember object
|
|
ClusterMember *new_member = createMember(fw, iface, master);
|
|
if (new_member == NULL)
|
|
{
|
|
qWarning() << "clusterMembersDialog: could not create new "
|
|
"cluster member";
|
|
return;
|
|
}
|
|
// attach to selected list
|
|
selected.push_back(new_member);
|
|
}
|
|
}
|
|
|
|
void clusterMembersDialog::getPossibleMembers()
|
|
{
|
|
t_fwList fwlist;
|
|
|
|
mw->findAllFirewalls(fwlist);
|
|
|
|
Firewall *fw;
|
|
for (t_fwList::iterator it = fwlist.begin(); it != fwlist.end(); it++)
|
|
{
|
|
// does host_OS and platform match?
|
|
fw = *it;
|
|
if (fw->getStr("host_OS").c_str() != host_os ||
|
|
fw->getStr("platform").c_str() != platform)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// does the firewall provide at least one phys. interface?
|
|
FWObjectTypedChildIterator iface_i = fw->findByType(Interface::TYPENAME);
|
|
if (iface_i == iface_i.end())
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// previously selected? skip
|
|
PredFindFw pred;
|
|
pred.setSearchString(fw->getName().c_str());
|
|
t_memberList::iterator it = find_if(selected.begin(),
|
|
selected.end(), pred);
|
|
if (it != selected.end())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// valid member, add to member list
|
|
ClusterMember *new_member = createMember(fw);
|
|
if (new_member == NULL)
|
|
{
|
|
qWarning() << "clusterMembersDialog: could not create new "
|
|
"cluster member";
|
|
return;
|
|
}
|
|
available.push_back(new_member);
|
|
}
|
|
}
|
|
fwlist.sort(FWObjectNameCmpPredicate());
|
|
}
|
|
|
|
void clusterMembersDialog::updateSelectedTable()
|
|
{
|
|
table_update = true;
|
|
m_dialog->fwSelectedTable->setRowCount(selected.size());
|
|
|
|
QTableWidgetItem *item = NULL;
|
|
int row = 0;
|
|
for (t_memberList::const_iterator it = selected.begin();
|
|
it != selected.end(); it++)
|
|
{
|
|
|
|
// only insert new QTableWidgetItems if none has been set, update text
|
|
// if selected member text changed.
|
|
|
|
item = m_dialog->fwSelectedTable->item(row, 0);
|
|
const char *new_text = (*it)->fwobj->getName().c_str();
|
|
if (item == NULL)
|
|
{
|
|
item = new QTableWidgetItem;
|
|
item->setText(new_text);
|
|
item->setIcon(QIcon(getIcon((*it)->fwobj)));
|
|
m_dialog->fwSelectedTable->setItem(row, 0, item);
|
|
}
|
|
else if (item->text() != new_text)
|
|
{
|
|
item->setText(new_text);
|
|
}
|
|
|
|
// Column "Interface"
|
|
item = m_dialog->fwSelectedTable->item(row, 1);
|
|
new_text = (*it)->iface_cluster->getName().c_str();
|
|
if (item == NULL)
|
|
{
|
|
item = new QTableWidgetItem;
|
|
item->setText(new_text);
|
|
item->setIcon(QIcon(getIcon((*it)->iface_cluster)));
|
|
m_dialog->fwSelectedTable->setItem(row, 1, item);
|
|
}
|
|
else if (item->text() != new_text)
|
|
{
|
|
item->setText(new_text);
|
|
}
|
|
|
|
// Column "Master"
|
|
item = m_dialog->fwSelectedTable->item(row, 2);
|
|
Qt::CheckState state = (*it)->is_master ? Qt::Checked : Qt::Unchecked;
|
|
if (item == NULL)
|
|
{
|
|
item = new QTableWidgetItem;
|
|
item->setCheckState(state);
|
|
m_dialog->fwSelectedTable->setItem(row, 2, item);
|
|
}
|
|
else if (item->checkState() != state)
|
|
{
|
|
item->setCheckState(state);
|
|
}
|
|
|
|
row++;
|
|
}
|
|
|
|
m_dialog->fwSelectedTable->resizeColumnsToContents();
|
|
m_dialog->fwSelectedTable->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
table_update = false;
|
|
}
|
|
|
|
void clusterMembersDialog::updateAvailableTree()
|
|
{
|
|
QTreeWidgetItem *fwitem;
|
|
|
|
m_dialog->fwAvailableTree->clear();
|
|
for (t_memberList::const_iterator it = available.begin();
|
|
it != available.end(); it++)
|
|
{
|
|
|
|
ClusterMember *member = *it;
|
|
fwitem = new QTreeWidgetItem;
|
|
fwitem->setFlags(Qt::ItemIsEnabled);
|
|
fwitem->setText(0, member->fwobj->getName().c_str());
|
|
fwitem->setIcon(0, QIcon(getIcon(member->fwobj)));
|
|
|
|
// add interfaces
|
|
for (t_ifaceList::const_iterator it = member->iface_list.begin();
|
|
it != member->iface_list.end(); it ++)
|
|
{
|
|
QTreeWidgetItem *ifitem;
|
|
ifitem = new QTreeWidgetItem(fwitem);
|
|
|
|
ifitem->setText(1, (*it)->getName().c_str());
|
|
ifitem->setIcon(1, QIcon(getIcon(*it)));
|
|
|
|
// add label (if non empty)
|
|
string label = (*it)->getLabel();
|
|
if (!label.empty())
|
|
{
|
|
ifitem->setText(2, label.c_str());
|
|
}
|
|
}
|
|
m_dialog->fwAvailableTree->insertTopLevelItem(0, fwitem);
|
|
}
|
|
|
|
m_dialog->fwAvailableTree->resizeColumnToContents(0);
|
|
m_dialog->fwAvailableTree->sortByColumn(0, Qt::AscendingOrder);
|
|
m_dialog->fwAvailableTree->expandAll();
|
|
}
|
|
|
|
ClusterMember*
|
|
clusterMembersDialog::createMember(Firewall *fw,
|
|
Interface *cluster_iface, bool master)
|
|
{
|
|
if (fw == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ClusterMember *new_member = new ClusterMember;
|
|
new_member->fwobj = fw;
|
|
new_member->is_master = master;
|
|
if (cluster_iface != NULL)
|
|
{
|
|
new_member->iface_cluster = cluster_iface;
|
|
}
|
|
|
|
list<FWObject*> interfaces = fw->getByTypeDeep(Interface::TYPENAME);
|
|
interfaces.sort(FWObjectNameCmpPredicate());
|
|
|
|
list<FWObject*>::iterator iface_i;
|
|
for (iface_i=interfaces.begin(); iface_i != interfaces.end(); ++iface_i)
|
|
{
|
|
Interface *iface = Interface::cast(*iface_i);
|
|
new_member->iface_list.push_back(iface);
|
|
// init interface mapping table
|
|
new_member->iface_map[iface->getName().c_str()] = iface;
|
|
}
|
|
return new_member;
|
|
}
|
|
|
|
bool clusterMembersDialog::swap(t_memberList &from, t_memberList &to,
|
|
const QString fwname, const QString iface, bool master)
|
|
{
|
|
// move selected fw from 'from' to 'to' member list
|
|
PredFindFw pred;
|
|
pred.setSearchString(fwname);
|
|
t_memberList::iterator it = find_if(from.begin(), from.end(), pred);
|
|
if (it == from.end())
|
|
{
|
|
// not found
|
|
return false;
|
|
}
|
|
|
|
ClusterMember *member = *it;
|
|
from.erase(it);
|
|
|
|
member->iface_cluster = member->iface_map[iface];
|
|
member->is_master = master;
|
|
to.push_back(member);
|
|
|
|
return true;
|
|
}
|
|
|
|
void clusterMembersDialog::setMaster(QString fw, bool checked)
|
|
{
|
|
for (t_memberList::const_iterator it = selected.begin();
|
|
it != selected.end(); it++)
|
|
{
|
|
if (QString((*it)->fwobj->getName().c_str()) == fw)
|
|
{
|
|
(*it)->is_master = checked;
|
|
}
|
|
else
|
|
{
|
|
(*it)->is_master = false;
|
|
}
|
|
}
|
|
updateSelectedTable();
|
|
}
|
|
|
|
QPixmap clusterMembersDialog::getIcon(FWObject *o)
|
|
{
|
|
QString icn_file = (":/Icons/" + o->getTypeName() +
|
|
"/icon").c_str();
|
|
|
|
QPixmap pm;
|
|
if (!QPixmapCache::find(icn_file, pm))
|
|
{
|
|
pm.load(icn_file);
|
|
QPixmapCache::insert(icn_file, pm);
|
|
}
|
|
return pm;
|
|
}
|
|
|
|
void clusterMembersDialog::invalidate()
|
|
{
|
|
// update views
|
|
updateAvailableTree();
|
|
updateSelectedTable();
|
|
|
|
// disable <--> buttons, user needs to re-select
|
|
m_dialog->buttonAdd->setEnabled(false);
|
|
m_dialog->buttonRemove->setEnabled(false);
|
|
}
|
|
|
|
void clusterMembersDialog::accept()
|
|
{
|
|
ProjectPanel *project = mw->activeProject();
|
|
std::auto_ptr<FWCmdChange> cmd( new FWCmdChange(project, obj));
|
|
FWObject* new_state = cmd->getNewState();
|
|
|
|
bool master_found = false;
|
|
t_memberList::const_iterator it = selected.begin();
|
|
|
|
// remoive all existing references and add new ones
|
|
list<FWObject*> all_refs = new_state->getByType(FWObjectReference::TYPENAME);
|
|
for (list<FWObject*>::iterator it=all_refs.begin(); it!=all_refs.end(); ++it)
|
|
new_state->remove(*it);
|
|
|
|
// add selected interfaces as objref to cluster member group
|
|
for (it = selected.begin(); it != selected.end(); it++)
|
|
{
|
|
new_state->addRef((*it)->iface_cluster);
|
|
// set master interface ref id
|
|
if ((*it)->is_master)
|
|
{
|
|
master_found = true;
|
|
std::string masteriface_id =
|
|
FWObjectDatabase::getStringId((*it)->iface_cluster->getId());
|
|
new_state->setStr("master_iface", masteriface_id);
|
|
}
|
|
}
|
|
if (!master_found)
|
|
{
|
|
new_state->remStr("master_iface");
|
|
}
|
|
emit membersChanged();
|
|
|
|
if (!cmd->getOldState()->cmp(new_state, true))
|
|
project->undoStack->push(cmd.release());
|
|
|
|
QDialog::accept();
|
|
}
|
|
|
|
void clusterMembersDialog::reject()
|
|
{
|
|
QDialog::reject();
|
|
}
|
|
|
|
void clusterMembersDialog::help()
|
|
{
|
|
QString tab_title = m_dialog->tabWidget->tabText(
|
|
m_dialog->tabWidget->currentIndex());
|
|
QString anchor = tab_title.replace('/', '-').replace(' ', '-').toLower();
|
|
Help *h = Help::getHelpWindow(this);
|
|
h->setName("Cluster-Member Management");
|
|
h->setSource(QUrl("clusterMembersDialog.html#" + anchor));
|
|
h->raise();
|
|
h->show();
|
|
}
|
|
|
|
void clusterMembersDialog::availableClicked(QTreeWidgetItem *item, int)
|
|
{
|
|
// activate addButton if a specific interface has been selected
|
|
if (item->text(1).isEmpty())
|
|
{
|
|
m_dialog->buttonAdd->setEnabled(false);
|
|
}
|
|
else if (!m_dialog->buttonAdd->isEnabled())
|
|
{
|
|
m_dialog->buttonAdd->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void clusterMembersDialog::selectedClicked(int row, int column)
|
|
{
|
|
if (fwbdebug)
|
|
{
|
|
qDebug() << "clusterMembersDialog: selected (" << row << ", "
|
|
<< column << ")";
|
|
}
|
|
|
|
// activate removeButton
|
|
if (!m_dialog->buttonRemove->isEnabled())
|
|
{
|
|
m_dialog->buttonRemove->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void clusterMembersDialog::masterSelected(int row, int column)
|
|
{
|
|
if (!table_update)
|
|
{
|
|
if (fwbdebug)
|
|
{
|
|
qDebug() << "clusterMembersDialog: master is (" << row
|
|
<< ", " << column << ")";
|
|
}
|
|
|
|
QList<QTableWidgetItem *> itemlist;
|
|
itemlist = m_dialog->fwSelectedTable->selectedItems();
|
|
|
|
if (itemlist[2]->checkState() == Qt::Checked)
|
|
{
|
|
setMaster(itemlist[0]->text());
|
|
}
|
|
else
|
|
{
|
|
setMaster(itemlist[0]->text(), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void clusterMembersDialog::firewallAdd()
|
|
{
|
|
// get selected firewall / interface
|
|
QList<QTreeWidgetItem *> itemlist;
|
|
itemlist = m_dialog->fwAvailableTree->selectedItems();
|
|
|
|
// interface should not be empty
|
|
if (itemlist[0]->text(1).isEmpty())
|
|
{
|
|
qWarning() << "clusterMembersDialog: iface is empty, not adding";
|
|
return;
|
|
}
|
|
|
|
foreach(QTreeWidgetItem *itm, itemlist)
|
|
{
|
|
// move selected fw to selected member list
|
|
QString fwname = itm->parent()->text(0);
|
|
QString iface_cluster = itm->text(1);
|
|
if (!swap(available, selected, fwname, iface_cluster))
|
|
{
|
|
// swap failed, this should not happen!
|
|
qWarning() << "clusterMembersDialog: swap failed for firewall "
|
|
<< fwname << ", interface: " << iface_cluster;
|
|
return;
|
|
}
|
|
}
|
|
// invalidate view
|
|
invalidate();
|
|
}
|
|
|
|
void clusterMembersDialog::firewallRemove()
|
|
{
|
|
// get selected firewall / interface
|
|
QList<QTableWidgetItem *> itemlist;
|
|
itemlist = m_dialog->fwSelectedTable->selectedItems();
|
|
|
|
// move selected fw to available member list
|
|
QString fwname = itemlist[0]->text();
|
|
if (!swap(selected, available, fwname, "", false))
|
|
{
|
|
// swap failed, this should not happen!
|
|
qWarning() << "clusterMembersDialog: swap failed for firewall "
|
|
<< fwname;
|
|
return;
|
|
}
|
|
// invalidate view
|
|
invalidate();
|
|
}
|
|
|