Skip to content

Commit

Permalink
Merge pull request #6315
Browse files Browse the repository at this point in the history
7aac6db [QT] dump banlist to disk in case of ban/unban over QT (Jonas Schnelli)
7f90ea7 [QA] adabt QT_NO_KEYWORDS for QT ban implementation (Jonas Schnelli)
07f70b2 [QA] fix netbase tests because of new CSubNet::ToString() output (Jonas Schnelli)
4ed0510 [Qt] call DumpBanlist() when baning unbaning nodes (Philip Kaufmann)
be89292 [Qt] reenabling hotkeys for ban context menu, use different words (Jonas Schnelli)
b1189cf [Qt] adapt QT ban option to banlist.dat changes (Jonas Schnelli)
65abe91 [Qt] add sorting for bantable (Philip Kaufmann)
51654de [Qt] bantable polish (Philip Kaufmann)
cdd72cd [Qt] simplify ban list signal handling (Philip Kaufmann)
43c1f5b [Qt] remove unused timer-code from banlistmodel.cpp (Jonas Schnelli)
e2b8028 net: Fix CIDR notation in ToString() (Wladimir J. van der Laan)
9e521c1 [Qt] polish ban table (Philip Kaufmann)
607809f net: use CIDR notation in CSubNet::ToString() (Jonas Schnelli)
53caec6 [Qt] bantable overhaul (Jonas Schnelli)
f0bcbc4 [Qt] bantable fix timestamp 64bit issue (Jonas Schnelli)
6135309 [Qt] banlist, UI optimizing and better signal handling (Jonas Schnelli)
770ca79 [Qt] add context menu with unban option to ban table (Jonas Schnelli)
5f42132 [Qt] add ui signal for banlist changes (Jonas Schnelli)
ad204df [Qt] add banlist table below peers table (Jonas Schnelli)
50f0908 [Qt] add ban functions to peers window (Jonas Schnelli)
  • Loading branch information
laanwj committed Sep 22, 2015
2 parents 28d0b3e + 7aac6db commit e59d2a8
Show file tree
Hide file tree
Showing 14 changed files with 654 additions and 56 deletions.
8 changes: 4 additions & 4 deletions qa/rpc-tests/nodehandling.py
Expand Up @@ -55,17 +55,17 @@ def run_test(self):
self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds
self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds
listBeforeShutdown = self.nodes[2].listbanned();
assert_equal("192.168.0.1/255.255.255.255", listBeforeShutdown[2]['address']) #must be here
assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here
time.sleep(2) #make 100% sure we expired 192.168.0.1 node time

#stop node
stop_node(self.nodes[2], 2)

self.nodes[2] = start_node(2, self.options.tmpdir)
listAfterShutdown = self.nodes[2].listbanned();
assert_equal("127.0.0.0/255.255.255.0", listAfterShutdown[0]['address'])
assert_equal("127.0.0.0/255.255.255.255", listAfterShutdown[1]['address'])
assert_equal("2001:4000::/ffff:e000:0:0:0:0:0:0", listAfterShutdown[2]['address'])
assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
assert_equal("/19" in listAfterShutdown[2]['address'], True)

###########################
# RPC disconnectnode test #
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.qt.include
Expand Up @@ -97,6 +97,7 @@ QT_MOC_CPP = \
qt/moc_addressbookpage.cpp \
qt/moc_addresstablemodel.cpp \
qt/moc_askpassphrasedialog.cpp \
qt/moc_bantablemodel.cpp \
qt/moc_bitcoinaddressvalidator.cpp \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoingui.cpp \
Expand Down Expand Up @@ -162,6 +163,7 @@ BITCOIN_QT_H = \
qt/addressbookpage.h \
qt/addresstablemodel.h \
qt/askpassphrasedialog.h \
qt/bantablemodel.h \
qt/bitcoinaddressvalidator.h \
qt/bitcoinamountfield.h \
qt/bitcoingui.h \
Expand Down Expand Up @@ -260,6 +262,7 @@ RES_ICONS = \
qt/res/icons/verify.png

BITCOIN_QT_CPP = \
qt/bantablemodel.cpp \
qt/bitcoinaddressvalidator.cpp \
qt/bitcoinamountfield.cpp \
qt/bitcoingui.cpp \
Expand Down
56 changes: 48 additions & 8 deletions src/netbase.cpp
Expand Up @@ -1311,17 +1311,57 @@ bool CSubNet::Match(const CNetAddr &addr) const
return true;
}

static inline int NetmaskBits(uint8_t x)
{
switch(x) {
case 0x00: return 0; break;
case 0x80: return 1; break;
case 0xc0: return 2; break;
case 0xe0: return 3; break;
case 0xf0: return 4; break;
case 0xf8: return 5; break;
case 0xfc: return 6; break;
case 0xfe: return 7; break;
case 0xff: return 8; break;
default: return -1; break;
}
}

std::string CSubNet::ToString() const
{
/* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
int cidr = 0;
bool valid_cidr = true;
int n = network.IsIPv4() ? 12 : 0;
for (; n < 16 && netmask[n] == 0xff; ++n)
cidr += 8;
if (n < 16) {
int bits = NetmaskBits(netmask[n]);
if (bits < 0)
valid_cidr = false;
else
cidr += bits;
++n;
}
for (; n < 16 && valid_cidr; ++n)
if (netmask[n] != 0x00)
valid_cidr = false;

/* Format output */
std::string strNetmask;
if (network.IsIPv4())
strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
else
strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
if (valid_cidr) {
strNetmask = strprintf("%u", cidr);
} else {
if (network.IsIPv4())
strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
else
strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
}

return network.ToString() + "/" + strNetmask;
}

Expand Down
181 changes: 181 additions & 0 deletions src/qt/bantablemodel.cpp
@@ -0,0 +1,181 @@
// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bantablemodel.h"

#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"

#include "sync.h"
#include "utiltime.h"

#include <QDebug>
#include <QList>

bool BannedNodeLessThan::operator()(const CCombinedBan& left, const CCombinedBan& right) const
{
const CCombinedBan* pLeft = &left;
const CCombinedBan* pRight = &right;

if (order == Qt::DescendingOrder)
std::swap(pLeft, pRight);

switch(column)
{
case BanTableModel::Address:
return pLeft->subnet.ToString().compare(pRight->subnet.ToString()) < 0;
case BanTableModel::Bantime:
return pLeft->banEntry.nBanUntil < pRight->banEntry.nBanUntil;
}

return false;
}

// private implementation
class BanTablePriv
{
public:
/** Local cache of peer information */
QList<CCombinedBan> cachedBanlist;
/** Column to sort nodes by */
int sortColumn;
/** Order (ascending or descending) to sort nodes by */
Qt::SortOrder sortOrder;

/** Pull a full list of banned nodes from CNode into our cache */
void refreshBanlist()
{
banmap_t banMap;
CNode::GetBanned(banMap);

cachedBanlist.clear();
#if QT_VERSION >= 0x040700
cachedBanlist.reserve(banMap.size());
#endif
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
{
CCombinedBan banEntry;
banEntry.subnet = (*it).first;
banEntry.banEntry = (*it).second;
cachedBanlist.append(banEntry);
}

if (sortColumn >= 0)
// sort cachedBanlist (use stable sort to prevent rows jumping around unneceesarily)
qStableSort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder));
}

int size() const
{
return cachedBanlist.size();
}

CCombinedBan *index(int idx)
{
if (idx >= 0 && idx < cachedBanlist.size())
return &cachedBanlist[idx];

return 0;
}
};

BanTableModel::BanTableModel(ClientModel *parent) :
QAbstractTableModel(parent),
clientModel(parent)
{
columns << tr("IP/Netmask") << tr("Banned Until");
priv = new BanTablePriv();
// default to unsorted
priv->sortColumn = -1;

// load initial data
refresh();
}

int BanTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return priv->size();
}

int BanTableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return columns.length();;
}

QVariant BanTableModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
return QVariant();

CCombinedBan *rec = static_cast<CCombinedBan*>(index.internalPointer());

if (role == Qt::DisplayRole) {
switch(index.column())
{
case Address:
return QString::fromStdString(rec->subnet.ToString());
case Bantime:
QDateTime date = QDateTime::fromMSecsSinceEpoch(0);
date = date.addSecs(rec->banEntry.nBanUntil);
return date.toString(Qt::SystemLocaleLongDate);
}
}

return QVariant();
}

QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Horizontal)
{
if(role == Qt::DisplayRole && section < columns.size())
{
return columns[section];
}
}
return QVariant();
}

Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const
{
if(!index.isValid())
return 0;

Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
return retval;
}

QModelIndex BanTableModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(parent);
CCombinedBan *data = priv->index(row);

if (data)
return createIndex(row, column, data);
return QModelIndex();
}

void BanTableModel::refresh()
{
Q_EMIT layoutAboutToBeChanged();
priv->refreshBanlist();
Q_EMIT layoutChanged();
}

void BanTableModel::sort(int column, Qt::SortOrder order)
{
priv->sortColumn = column;
priv->sortOrder = order;
refresh();
}

bool BanTableModel::shouldShow()
{
if (priv->size() > 0)
return true;
return false;
}
72 changes: 72 additions & 0 deletions src/qt/bantablemodel.h
@@ -0,0 +1,72 @@
// Copyright (c) 2011-2013 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_QT_BANTABLEMODEL_H
#define BITCOIN_QT_BANTABLEMODEL_H

#include "net.h"

#include <QAbstractTableModel>
#include <QStringList>

class ClientModel;
class BanTablePriv;

struct CCombinedBan {
CSubNet subnet;
CBanEntry banEntry;
};

class BannedNodeLessThan
{
public:
BannedNodeLessThan(int nColumn, Qt::SortOrder fOrder) :
column(nColumn), order(fOrder) {}
bool operator()(const CCombinedBan& left, const CCombinedBan& right) const;

private:
int column;
Qt::SortOrder order;
};

/**
Qt model providing information about connected peers, similar to the
"getpeerinfo" RPC call. Used by the rpc console UI.
*/
class BanTableModel : public QAbstractTableModel
{
Q_OBJECT

public:
explicit BanTableModel(ClientModel *parent = 0);
void startAutoRefresh();
void stopAutoRefresh();

enum ColumnIndex {
Address = 0,
Bantime = 1
};

/** @name Methods overridden from QAbstractTableModel
@{*/
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
void sort(int column, Qt::SortOrder order);
bool shouldShow();
/*@}*/

public Q_SLOTS:
void refresh();

private:
ClientModel *clientModel;
QStringList columns;
BanTablePriv *priv;
};

#endif // BITCOIN_QT_BANTABLEMODEL_H

0 comments on commit e59d2a8

Please sign in to comment.