Commit 4a3bfcf2 authored by Georgios Bitzes's avatar Georgios Bitzes
Browse files

Prevent sneaky clients from issuing timestamped lease commands

The lease commands are to be timestamped by the server, not
the client. Let's just pretend to sneaky clients that
timestamped lease commands simply do not exist.
parent b0ee9e0c
Pipeline #430712 passed with stages
in 47 minutes and 27 seconds
......@@ -59,6 +59,7 @@ add_library(XrdQuarkDB SHARED
redis/ArrayResponseBuilder.cc redis/ArrayResponseBuilder.hh
redis/Authenticator.cc redis/Authenticator.hh
redis/InternalFilter.cc redis/InternalFilter.hh
redis/CommandMonitor.cc redis/CommandMonitor.hh
redis/LeaseFilter.cc redis/LeaseFilter.hh
redis/MultiHandler.cc redis/MultiHandler.hh
......
......@@ -25,6 +25,7 @@
#include "Dispatcher.hh"
#include "Formatter.hh"
#include "utils/InFlightTracker.hh"
#include "redis/InternalFilter.hh"
using namespace quarkdb;
LinkStatus PendingQueue::flushPending(const RedisEncodedResponse &msg) {
......@@ -219,6 +220,7 @@ LinkStatus Connection::processRequests(Dispatcher *dispatcher, const InFlightTra
}
LinkStatus status = parser.fetch(currentRequest);
InternalFilter::process(currentRequest);
if(status < 0) {
return status; // link error
......
......@@ -118,6 +118,12 @@ public:
void parseCommand();
std::string toPrintableString() const;
void invalidate() {
command = RedisCommand::INVALID;
commandType = CommandType::INVALID;
}
private:
std::vector<std::string> contents;
RedisCommand command = RedisCommand::INVALID;
......
// ----------------------------------------------------------------------
// File: InternalFilter.cc
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2018 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
************************************************************************/
#include "InternalFilter.hh"
#include "../RedisRequest.hh"
using namespace quarkdb;
void InternalFilter::process(RedisRequest &req) {
switch(req.getCommand()) {
case RedisCommand::TIMESTAMPED_LEASE_ACQUIRE:
case RedisCommand::TIMESTAMPED_LEASE_GET: {
// Bad client, bad. No cookie for you.
req.invalidate();
}
default: {
// All is good, do nothing.
return;
}
}
}
// ----------------------------------------------------------------------
// File: InternalFilter.hh
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2018 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
************************************************************************/
#ifndef QUARKDB_REDIS_INTERNAL_FILTER_H
#define QUARKDB_REDIS_INTERNAL_FILTER_H
namespace quarkdb {
class RedisRequest;
class InternalFilter {
public:
//----------------------------------------------------------------------------
// Invalidate commands which an end-user has no business emitting, such as
// TIMESTAMPED_LEASE_GET, TIMESTAMPED_LEASE_ACQUIRE. These can only be
// generated internally.
//----------------------------------------------------------------------------
static void process(RedisRequest &req);
};
}
#endif
......@@ -328,6 +328,7 @@ TEST_F(Raft_e2e, test_many_redis_commands) {
futures.emplace_back(tunnel(leaderID)->exec("scard", "myset"));
futures.emplace_back(tunnel(leaderID)->exec("smembers", "myset"));
futures.emplace_back(tunnel(leaderID)->exec("get", "empty_key"));
futures.emplace_back(tunnel(leaderID)->exec("timestamped-lease-acquire", "123"));
ASSERT_REPLY(futures[0], 3);
ASSERT_REPLY(futures[1], 3);
......@@ -337,6 +338,7 @@ TEST_F(Raft_e2e, test_many_redis_commands) {
ASSERT_REPLY(futures[5], 1);
ASSERT_REPLY(futures[6], make_vec("c"));
ASSERT_NIL(futures[7]);
ASSERT_REPLY(futures[8], "ERR unknown command 'timestamped-lease-acquire'" );
futures.clear();
......
......@@ -35,6 +35,7 @@
#include "redis/Transaction.hh"
#include "redis/Authenticator.hh"
#include "redis/LeaseFilter.hh"
#include "redis/InternalFilter.hh"
#include "redis/RedisEncodedResponse.hh"
#include "Utils.hh"
#include "Formatter.hh"
......@@ -466,3 +467,20 @@ TEST(LeaseFilter, BasicSanity) {
ASSERT_EQ(req[2], unsignedIntToBinaryString(567));
ASSERT_EQ(req.getCommand(), RedisCommand::TIMESTAMPED_LEASE_GET);
}
TEST(InternalFilter, BasicSanity) {
RedisRequest req = {"timestamped_lease_get", "asdf" };
ASSERT_EQ(req.getCommand(), RedisCommand::TIMESTAMPED_LEASE_GET);
InternalFilter::process(req);
ASSERT_EQ(req.getCommand(), RedisCommand::INVALID);
req = {"timestamped_lease_acquire", "asdfas" };
ASSERT_EQ(req.getCommand(), RedisCommand::TIMESTAMPED_LEASE_ACQUIRE);
InternalFilter::process(req);
ASSERT_EQ(req.getCommand(), RedisCommand::INVALID);
req = {"set", "adsfasf", "qerq"};
ASSERT_EQ(req.getCommand(), RedisCommand::SET);
InternalFilter::process(req);
ASSERT_EQ(req.getCommand(), RedisCommand::SET);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment