Merge pull request #9053 from huffman/feat/whitelist-ac-ip

Add AC ip address whitelist to domain server
This commit is contained in:
Clément Brisset 2016-11-11 15:03:21 -08:00 committed by GitHub
commit e38da75115
5 changed files with 79 additions and 3 deletions

View file

@ -388,6 +388,23 @@
"default": "",
"advanced": false
},
{
"name": "ac_subnet_whitelist",
"label": "Assignment Client IP address Whitelist",
"type": "table",
"can_add_new_rows": true,
"help": "The IP addresses or subnets of ACs that can connect to this server. You can specify an IP address or a subnet in CIDR notation ('A.B.C.D/E', Example: '10.0.0.0/24'). Local ACs (localhost) are always permitted and do not need to be added here.",
"numbered": false,
"advanced": true,
"columns": [
{
"name": "ip",
"label": "IP Address",
"type": "ip",
"can_set": true
}
]
},
{
"name": "standard_permissions",
"type": "table",

View file

@ -158,6 +158,42 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qDebug() << "domain-server is running";
static const QString AC_SUBNET_WHITELIST_SETTING_PATH = "security.ac_subnet_whitelist";
static const Subnet LOCALHOST { QHostAddress("127.0.0.1"), 32 };
_acSubnetWhitelist = { LOCALHOST };
auto whitelist = _settingsManager.valueOrDefaultValueForKeyPath(AC_SUBNET_WHITELIST_SETTING_PATH).toStringList();
for (auto& subnet : whitelist) {
auto netmaskParts = subnet.trimmed().split("/");
if (netmaskParts.size() > 2) {
qDebug() << "Ignoring subnet in whitelist, malformed: " << subnet;
continue;
}
// The default netmask is 32 if one has not been specified, which will
// match only the ip provided.
int netmask = 32;
if (netmaskParts.size() == 2) {
bool ok;
netmask = netmaskParts[1].toInt(&ok);
if (!ok) {
qDebug() << "Ignoring subnet in whitelist, bad netmask: " << subnet;
continue;
}
}
auto ip = QHostAddress(netmaskParts[0]);
if (!ip.isNull()) {
qDebug() << "Adding AC whitelist subnet: " << subnet << " -> " << (ip.toString() + "/" + QString::number(netmask));
_acSubnetWhitelist.push_back({ ip , netmask });
} else {
qDebug() << "Ignoring subnet in whitelist, invalid ip portion: " << subnet;
}
}
}
void DomainServer::parseCommandLine() {
@ -1001,6 +1037,21 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer<ReceivedMessage
// construct the requested assignment from the packet data
Assignment requestAssignment(*message);
auto senderAddr = message->getSenderSockAddr().getAddress();
auto isHostAddressInSubnet = [&senderAddr](const Subnet& mask) -> bool {
return senderAddr.isInSubnet(mask);
};
auto it = find_if(_acSubnetWhitelist.begin(), _acSubnetWhitelist.end(), isHostAddressInSubnet);
if (it == _acSubnetWhitelist.end()) {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
"Received an assignment connect request from a disallowed ip address: [^ ]+");
qDebug() << "Received an assignment connect request from a disallowed ip address:"
<< senderAddr.toString();
return;
}
// Suppress these for Assignment::AgentType to once per 5 seconds
static QElapsedTimer noisyMessageTimer;
static bool wasNoisyTimerStarted = false;

View file

@ -36,6 +36,9 @@
typedef QSharedPointer<Assignment> SharedAssignmentPointer;
typedef QMultiHash<QUuid, WalletTransaction*> TransactionHash;
using Subnet = QPair<QHostAddress, int>;
using SubnetList = std::vector<Subnet>;
class DomainServer : public QCoreApplication, public HTTPSRequestHandler {
Q_OBJECT
public:
@ -156,6 +159,8 @@ private:
void setupGroupCacheRefresh();
SubnetList _acSubnetWhitelist;
DomainGatekeeper _gatekeeper;
HTTPManager _httpManager;

View file

@ -1077,6 +1077,9 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
}
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) {
static const QString SECURITY_ROOT_KEY = "security";
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
auto& settingsVariant = _configMap.getConfig();
bool needRestart = false;
@ -1127,7 +1130,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
if (!matchingDescriptionObject.isEmpty()) {
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
if (rootKey != "security") {
if (rootKey != SECURITY_ROOT_KEY) {
needRestart = true;
}
} else {
@ -1143,7 +1146,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
if (!matchingDescriptionObject.isEmpty()) {
QJsonValue settingValue = rootValue.toObject()[settingKey];
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
if (rootKey != "security") {
if (rootKey != SECURITY_ROOT_KEY || settingKey == AC_SUBNET_WHITELIST_KEY) {
needRestart = true;
}
} else {

View file

@ -226,5 +226,5 @@ QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath, bool
shouldCreateIfMissing);
}
return NULL;
return nullptr;
}