mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2024-12-14 11:58:02 +00:00
Add tls support and config flags simulating redis configuration params
This commit is contained in:
parent
bf714b1a64
commit
9282d96d00
7 changed files with 213 additions and 13 deletions
|
@ -1,13 +1,13 @@
|
||||||
add_executable(dragonfly dfly_main.cc)
|
add_executable(dragonfly dfly_main.cc)
|
||||||
cxx_link(dragonfly base dragonfly_lib)
|
cxx_link(dragonfly base dragonfly_lib)
|
||||||
|
|
||||||
add_library(dragonfly_lib command_registry.cc db_slice.cc dragonfly_listener.cc
|
add_library(dragonfly_lib command_registry.cc config_flags.cc db_slice.cc dragonfly_listener.cc
|
||||||
dragonfly_connection.cc
|
dragonfly_connection.cc
|
||||||
main_service.cc engine_shard_set.cc
|
main_service.cc engine_shard_set.cc
|
||||||
redis_parser.cc resp_expr.cc reply_builder.cc)
|
redis_parser.cc resp_expr.cc reply_builder.cc)
|
||||||
|
|
||||||
cxx_link(dragonfly_lib uring_fiber_lib
|
cxx_link(dragonfly_lib uring_fiber_lib
|
||||||
fibers_ext strings_lib http_server_lib)
|
fibers_ext strings_lib http_server_lib tls_lib)
|
||||||
|
|
||||||
add_library(dfly_test_lib test_utils.cc)
|
add_library(dfly_test_lib test_utils.cc)
|
||||||
cxx_link(dfly_test_lib dragonfly_lib gtest_main_ext)
|
cxx_link(dfly_test_lib dragonfly_lib gtest_main_ext)
|
||||||
|
|
19
server/config_flags.cc
Normal file
19
server/config_flags.cc
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2021, Beeri 15. All rights reserved.
|
||||||
|
// Author: Roman Gershman (romange@gmail.com)
|
||||||
|
//
|
||||||
|
#include "server/config_flags.h"
|
||||||
|
|
||||||
|
namespace dfly {
|
||||||
|
|
||||||
|
bool ValidateConfigEnum(const char* nm, const std::string& val, const ConfigEnum* ptr, unsigned len,
|
||||||
|
int* dest) {
|
||||||
|
for (unsigned i = 0; i < len; ++i) {
|
||||||
|
if (val == ptr[i].first) {
|
||||||
|
*dest = ptr[i].second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dfly
|
92
server/config_flags.h
Normal file
92
server/config_flags.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright 2021, Beeri 15. All rights reserved.
|
||||||
|
// Author: Roman Gershman (romange@gmail.com)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <absl/base/macros.h>
|
||||||
|
|
||||||
|
#include "base/flags.h"
|
||||||
|
|
||||||
|
namespace dfly {
|
||||||
|
|
||||||
|
// DashStr - replaces all underscores to dash characters and keeps the rest as is.
|
||||||
|
template <unsigned N> class DashStr {
|
||||||
|
public:
|
||||||
|
DashStr(const char* s) {
|
||||||
|
memcpy(str_, s, N);
|
||||||
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
|
if (str_[i] == '_')
|
||||||
|
str_[i] = '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* str() const {
|
||||||
|
return str_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char str_[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
using ConfigEnum = std::pair<const char*, int>;
|
||||||
|
|
||||||
|
bool ValidateConfigEnum(const char* nm, const std::string& val, const ConfigEnum* ptr, unsigned len,
|
||||||
|
int* dest);
|
||||||
|
|
||||||
|
} // namespace dfly
|
||||||
|
|
||||||
|
inline bool TrueValidator(const char* nm, const std::string& val) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_CONFIG_VAR(type, shorttype, name, value, help, validator) \
|
||||||
|
namespace fL##shorttype { \
|
||||||
|
type FLAGS_##name = value; \
|
||||||
|
static type FLAGS_no##name = value; \
|
||||||
|
static ::dfly::DashStr<sizeof(#name)> _dash_##name(#name); \
|
||||||
|
static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \
|
||||||
|
_dash_##name.str(), MAYBE_STRIPPED_HELP(help), __FILE__, &FLAGS_##name, &FLAGS_no##name); \
|
||||||
|
static const bool name##_val_reg = \
|
||||||
|
GFLAGS_NAMESPACE::RegisterFlagValidator(&FLAGS_##name, validator); \
|
||||||
|
} \
|
||||||
|
using fL##shorttype::FLAGS_##name
|
||||||
|
|
||||||
|
#define BIND_CONFIG(var) [](const char* nm, auto val) { \
|
||||||
|
var = val; \
|
||||||
|
return true;}
|
||||||
|
|
||||||
|
|
||||||
|
#define BIND_ENUM_CONFIG(enum_arr, dest_var) [](const char* nm, const std::string& val) { \
|
||||||
|
return ::dfly::ValidateConfigEnum(nm, val, enum_arr, ABSL_ARRAYSIZE(enum_arr), \
|
||||||
|
&(dest_var));}
|
||||||
|
|
||||||
|
#define CONFIG_uint64(name,val, txt, validator) \
|
||||||
|
DEFINE_CONFIG_VAR(GFLAGS_NAMESPACE::uint64, U64, name, val, txt, validator)
|
||||||
|
|
||||||
|
|
||||||
|
#define CONFIG_string(name, val, txt, validator) \
|
||||||
|
namespace fLS { \
|
||||||
|
using ::fLS::clstring; \
|
||||||
|
using ::fLS::StringFlagDestructor; \
|
||||||
|
static union { void* align; char s[sizeof(clstring)]; } s_##name[2]; \
|
||||||
|
clstring* const FLAGS_no##name = ::fLS:: \
|
||||||
|
dont_pass0toDEFINE_string(s_##name[0].s, \
|
||||||
|
val); \
|
||||||
|
static ::dfly::DashStr<sizeof(#name)> _dash_##name(#name); \
|
||||||
|
static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \
|
||||||
|
_dash_##name.str(), MAYBE_STRIPPED_HELP(txt), __FILE__, \
|
||||||
|
FLAGS_no##name, new (s_##name[1].s) clstring(*FLAGS_no##name)); \
|
||||||
|
static StringFlagDestructor d_##name(s_##name[0].s, s_##name[1].s); \
|
||||||
|
extern GFLAGS_DLL_DEFINE_FLAG clstring& FLAGS_##name; \
|
||||||
|
using fLS::FLAGS_##name; \
|
||||||
|
clstring& FLAGS_##name = *FLAGS_no##name; \
|
||||||
|
static const bool name##_val_reg = \
|
||||||
|
GFLAGS_NAMESPACE::RegisterFlagValidator(&FLAGS_##name, validator); \
|
||||||
|
} \
|
||||||
|
using fLS::FLAGS_##name
|
||||||
|
|
||||||
|
#define CONFIG_enum(name, val, txt, enum_arr, dest_var) \
|
||||||
|
CONFIG_string(name, val, txt, BIND_ENUM_CONFIG(enum_arr, dest_var))
|
||||||
|
|
|
@ -8,11 +8,12 @@
|
||||||
|
|
||||||
#include "base/io_buf.h"
|
#include "base/io_buf.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
#include "server/command_registry.h"
|
||||||
|
#include "server/conn_context.h"
|
||||||
#include "server/main_service.h"
|
#include "server/main_service.h"
|
||||||
#include "server/redis_parser.h"
|
#include "server/redis_parser.h"
|
||||||
#include "server/conn_context.h"
|
|
||||||
#include "server/command_registry.h"
|
|
||||||
#include "util/fiber_sched_algo.h"
|
#include "util/fiber_sched_algo.h"
|
||||||
|
#include "util/tls/tls_socket.h"
|
||||||
|
|
||||||
using namespace util;
|
using namespace util;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -68,8 +69,7 @@ struct Connection::Shutdown {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection::Connection(Service* service)
|
Connection::Connection(Service* service, SSL_CTX* ctx) : service_(service), ctx_(ctx) {
|
||||||
: service_(service) {
|
|
||||||
redis_parser_.reset(new RedisParser);
|
redis_parser_.reset(new RedisParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,19 @@ void Connection::HandleRequests() {
|
||||||
int val = 1;
|
int val = 1;
|
||||||
CHECK_EQ(0, setsockopt(socket_->native_handle(), SOL_TCP, TCP_NODELAY, &val, sizeof(val)));
|
CHECK_EQ(0, setsockopt(socket_->native_handle(), SOL_TCP, TCP_NODELAY, &val, sizeof(val)));
|
||||||
|
|
||||||
FiberSocketBase* peer = socket_.get();
|
std::unique_ptr<tls::TlsSocket> tls_sock;
|
||||||
|
if (ctx_) {
|
||||||
|
tls_sock.reset(new tls::TlsSocket(socket_.get()));
|
||||||
|
tls_sock->InitSSL(ctx_);
|
||||||
|
|
||||||
|
FiberSocketBase::accept_result aresult = tls_sock->Accept();
|
||||||
|
if (!aresult) {
|
||||||
|
LOG(WARNING) << "Error handshaking " << aresult.error().message();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VLOG(1) << "TLS handshake succeeded";
|
||||||
|
}
|
||||||
|
FiberSocketBase* peer = tls_sock ? (FiberSocketBase*)tls_sock.get() : socket_.get();
|
||||||
cc_.reset(new ConnectionContext(peer, this));
|
cc_.reset(new ConnectionContext(peer, this));
|
||||||
cc_->shard_set = &service_->shard_set();
|
cc_->shard_set = &service_->shard_set();
|
||||||
|
|
||||||
|
@ -132,7 +144,7 @@ void Connection::InputLoop(FiberSocketBase* peer) {
|
||||||
|
|
||||||
io_buf.CommitWrite(*recv_sz);
|
io_buf.CommitWrite(*recv_sz);
|
||||||
status = ParseRedis(&io_buf);
|
status = ParseRedis(&io_buf);
|
||||||
if (status == NEED_MORE) {
|
if (status == NEED_MORE) {
|
||||||
status = OK;
|
status = OK;
|
||||||
} else if (status != OK) {
|
} else if (status != OK) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,15 +8,17 @@
|
||||||
|
|
||||||
#include "base/io_buf.h"
|
#include "base/io_buf.h"
|
||||||
|
|
||||||
|
typedef struct ssl_ctx_st SSL_CTX;
|
||||||
|
|
||||||
namespace dfly {
|
namespace dfly {
|
||||||
|
|
||||||
class Service;
|
|
||||||
class RedisParser;
|
|
||||||
class ConnectionContext;
|
class ConnectionContext;
|
||||||
|
class RedisParser;
|
||||||
|
class Service;
|
||||||
|
|
||||||
class Connection : public util::Connection {
|
class Connection : public util::Connection {
|
||||||
public:
|
public:
|
||||||
Connection(Service* service);
|
Connection(Service* service, SSL_CTX* ctx);
|
||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
using error_code = std::error_code;
|
using error_code = std::error_code;
|
||||||
|
@ -39,9 +41,10 @@ class Connection : public util::Connection {
|
||||||
ParserStatus ParseRedis(base::IoBuf* buf);
|
ParserStatus ParseRedis(base::IoBuf* buf);
|
||||||
|
|
||||||
std::unique_ptr<RedisParser> redis_parser_;
|
std::unique_ptr<RedisParser> redis_parser_;
|
||||||
|
Service* service_;
|
||||||
|
SSL_CTX* ctx_;
|
||||||
std::unique_ptr<ConnectionContext> cc_;
|
std::unique_ptr<ConnectionContext> cc_;
|
||||||
|
|
||||||
Service* service_;
|
|
||||||
unsigned parser_error_ = 0;
|
unsigned parser_error_ = 0;
|
||||||
|
|
||||||
struct Shutdown;
|
struct Shutdown;
|
||||||
|
|
|
@ -4,25 +4,96 @@
|
||||||
|
|
||||||
#include "server/dragonfly_listener.h"
|
#include "server/dragonfly_listener.h"
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
#include "server/config_flags.h"
|
||||||
#include "server/dragonfly_connection.h"
|
#include "server/dragonfly_connection.h"
|
||||||
#include "util/proactor_pool.h"
|
#include "util/proactor_pool.h"
|
||||||
|
|
||||||
using namespace util;
|
using namespace util;
|
||||||
|
|
||||||
DEFINE_uint32(conn_threads, 0, "Number of threads used for handing server connections");
|
DEFINE_uint32(conn_threads, 0, "Number of threads used for handing server connections");
|
||||||
|
DEFINE_bool(tls, false, "");
|
||||||
|
|
||||||
|
CONFIG_string(tls_client_cert_file, "", "", TrueValidator);
|
||||||
|
CONFIG_string(tls_client_key_file, "", "", TrueValidator);
|
||||||
|
|
||||||
|
enum TlsClientAuth {
|
||||||
|
CL_AUTH_NO = 0,
|
||||||
|
CL_AUTH_YES = 1,
|
||||||
|
CL_AUTH_OPTIONAL = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
dfly::ConfigEnum tls_auth_clients_enum[] = {
|
||||||
|
{"no", CL_AUTH_NO},
|
||||||
|
{"yes", CL_AUTH_YES},
|
||||||
|
{"optional", CL_AUTH_OPTIONAL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tls_auth_clients_opt = CL_AUTH_YES;
|
||||||
|
|
||||||
|
CONFIG_enum(tls_auth_clients, "yes", "", tls_auth_clients_enum, tls_auth_clients_opt);
|
||||||
|
|
||||||
namespace dfly {
|
namespace dfly {
|
||||||
|
|
||||||
|
// To connect: openssl s_client -cipher "ADH:@SECLEVEL=0" -state -crlf -connect 127.0.0.1:6380
|
||||||
|
static SSL_CTX* CreateSslCntx() {
|
||||||
|
SSL_CTX* ctx = SSL_CTX_new(TLS_server_method());
|
||||||
|
|
||||||
|
if (FLAGS_tls_client_key_file.empty()) {
|
||||||
|
// To connect - use openssl s_client -cipher with either:
|
||||||
|
// "AECDH:@SECLEVEL=0" or "ADH:@SECLEVEL=0" setting.
|
||||||
|
CHECK_EQ(1, SSL_CTX_set_cipher_list(ctx, "aNULL"));
|
||||||
|
|
||||||
|
// To allow anonymous ciphers.
|
||||||
|
SSL_CTX_set_security_level(ctx, 0);
|
||||||
|
|
||||||
|
// you can still connect with redis-cli with :
|
||||||
|
// redis-cli --tls --insecure --tls-ciphers "ADH:@SECLEVEL=0"
|
||||||
|
LOG(WARNING)
|
||||||
|
<< "tls-client-key-file not set, no keys are loaded and anonymous ciphers are enabled. "
|
||||||
|
<< "Do not use in production!";
|
||||||
|
} else { // tls_client_key_file is set.
|
||||||
|
CHECK_EQ(1,
|
||||||
|
SSL_CTX_use_PrivateKey_file(ctx, FLAGS_tls_client_key_file.c_str(), SSL_FILETYPE_PEM));
|
||||||
|
|
||||||
|
if (!FLAGS_tls_client_cert_file.empty()) {
|
||||||
|
// TO connect with redis-cli you need both tls-client-key-file and tls-client-cert-file
|
||||||
|
// loaded. Use `redis-cli --tls -p 6380 --insecure PING` to test
|
||||||
|
|
||||||
|
CHECK_EQ(1, SSL_CTX_use_certificate_chain_file(ctx, FLAGS_tls_client_cert_file.c_str()));
|
||||||
|
}
|
||||||
|
CHECK_EQ(1, SSL_CTX_set_cipher_list(ctx, "DEFAULT"));
|
||||||
|
}
|
||||||
|
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
|
||||||
|
|
||||||
|
SSL_CTX_set_options(ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
||||||
|
|
||||||
|
unsigned mask = SSL_VERIFY_NONE;
|
||||||
|
|
||||||
|
// if (tls_auth_clients_opt)
|
||||||
|
// mask |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||||
|
SSL_CTX_set_verify(ctx, mask, NULL);
|
||||||
|
|
||||||
|
CHECK_EQ(1, SSL_CTX_set_dh_auto(ctx, 1));
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
Listener::Listener(Service* e) : engine_(e) {
|
Listener::Listener(Service* e) : engine_(e) {
|
||||||
|
if (FLAGS_tls) {
|
||||||
|
OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL);
|
||||||
|
ctx_ = CreateSslCntx();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Listener::~Listener() {
|
Listener::~Listener() {
|
||||||
|
SSL_CTX_free(ctx_);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Connection* Listener::NewConnection(ProactorBase* proactor) {
|
util::Connection* Listener::NewConnection(ProactorBase* proactor) {
|
||||||
return new Connection{engine_};
|
return new Connection{engine_, ctx_};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Listener::PreShutdown() {
|
void Listener::PreShutdown() {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include "util/listener_interface.h"
|
#include "util/listener_interface.h"
|
||||||
|
|
||||||
|
typedef struct ssl_ctx_st SSL_CTX;
|
||||||
|
|
||||||
namespace dfly {
|
namespace dfly {
|
||||||
|
|
||||||
class Service;
|
class Service;
|
||||||
|
@ -26,6 +28,7 @@ class Listener : public util::ListenerInterface {
|
||||||
Service* engine_;
|
Service* engine_;
|
||||||
|
|
||||||
std::atomic_uint32_t next_id_{0};
|
std::atomic_uint32_t next_id_{0};
|
||||||
|
SSL_CTX* ctx_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
Loading…
Reference in a new issue