diff --git a/arangod/RestServer/RestServerFeature.cpp b/arangod/RestServer/RestServerFeature.cpp index 17948be91c..a3c6c37ecc 100644 --- a/arangod/RestServer/RestServerFeature.cpp +++ b/arangod/RestServer/RestServerFeature.cpp @@ -65,7 +65,7 @@ #include "RestServer/QueryRegistryFeature.h" #include "RestServer/ServerFeature.h" #include "Scheduler/SchedulerFeature.h" -#include "Ssl/SslFeature.h" +#include "Ssl/SslServerFeature.h" #include "V8Server/V8DealerFeature.h" #include "VocBase/server.h" @@ -250,8 +250,8 @@ void RestServerFeature::buildServers() { // ssl endpoints if (endpointList.hasSsl()) { - SslFeature* ssl = - application_features::ApplicationServer::getFeature("Ssl"); + SslServerFeature* ssl = + application_features::ApplicationServer::getFeature("SslServer"); // check the ssl context if (ssl->sslContext() == nullptr) { diff --git a/arangod/RestServer/arangod.cpp b/arangod/RestServer/arangod.cpp index 9450c67679..12ff30e237 100644 --- a/arangod/RestServer/arangod.cpp +++ b/arangod/RestServer/arangod.cpp @@ -60,6 +60,7 @@ #include "RestServer/UpgradeFeature.h" #include "Scheduler/SchedulerFeature.h" #include "Ssl/SslFeature.h" +#include "Ssl/SslServerFeature.h" #include "Statistics/StatisticsFeature.h" #include "V8Server/FoxxQueuesFeature.h" #include "V8Server/V8DealerFeature.h" @@ -136,7 +137,7 @@ static int runServer(int argc, char** argv) { "Cluster", "Daemon", "Dispatcher", "Endpoint", "FoxxQueues", "LoggerBufferFeature", "RestServer", "Server", "Scheduler", - "Ssl", "Statistics", "Supervisor"}; + "SslServer", "Statistics", "Supervisor"}; int ret = EXIT_FAILURE; @@ -173,6 +174,7 @@ static int runServer(int argc, char** argv) { server.addFeature(new ServerFeature(&server, &ret)); server.addFeature(new ShutdownFeature(&server, {"UnitTests", "Script"})); server.addFeature(new SslFeature(&server)); + server.addFeature(new SslServerFeature(&server)); server.addFeature(new StatisticsFeature(&server)); server.addFeature(new TempFeature(&server, name)); server.addFeature(new UnitTestsFeature(&server, &ret)); diff --git a/arangosh/Benchmark/arangobench.cpp b/arangosh/Benchmark/arangobench.cpp index a516332abf..b8d11881f3 100644 --- a/arangosh/Benchmark/arangobench.cpp +++ b/arangosh/Benchmark/arangobench.cpp @@ -33,6 +33,7 @@ #include "Logger/LoggerFeature.h" #include "ProgramOptions/ProgramOptions.h" #include "Random/RandomFeature.h" +#include "Ssl/SslFeature.h" using namespace arangodb; using namespace arangodb::application_features; @@ -56,6 +57,7 @@ int main(int argc, char* argv[]) { server.addFeature(new LoggerFeature(&server, false)); server.addFeature(new RandomFeature(&server)); server.addFeature(new ShutdownFeature(&server, {"Bench"})); + server.addFeature(new SslFeature(&server)); server.addFeature(new TempFeature(&server, "arangobench")); server.addFeature(new VersionFeature(&server)); diff --git a/arangosh/Dump/arangodump.cpp b/arangosh/Dump/arangodump.cpp index 62ce894119..ebc19ac778 100644 --- a/arangosh/Dump/arangodump.cpp +++ b/arangosh/Dump/arangodump.cpp @@ -32,6 +32,7 @@ #include "Logger/LoggerFeature.h" #include "ProgramOptions/ProgramOptions.h" #include "Random/RandomFeature.h" +#include "Ssl/SslFeature.h" using namespace arangodb; using namespace arangodb::application_features; @@ -53,6 +54,7 @@ int main(int argc, char* argv[]) { server.addFeature(new LoggerFeature(&server, false)); server.addFeature(new RandomFeature(&server)); server.addFeature(new ShutdownFeature(&server, {"Dump"})); + server.addFeature(new SslFeature(&server)); server.addFeature(new VersionFeature(&server)); try { diff --git a/arangosh/Import/arangoimp.cpp b/arangosh/Import/arangoimp.cpp index 425bcfc33e..fa8ce71140 100644 --- a/arangosh/Import/arangoimp.cpp +++ b/arangosh/Import/arangoimp.cpp @@ -33,6 +33,7 @@ #include "Logger/LoggerFeature.h" #include "ProgramOptions/ProgramOptions.h" #include "Random/RandomFeature.h" +#include "Ssl/SslFeature.h" using namespace arangodb; using namespace arangodb::application_features; @@ -54,6 +55,7 @@ int main(int argc, char* argv[]) { server.addFeature(new LoggerFeature(&server, false)); server.addFeature(new RandomFeature(&server)); server.addFeature(new ShutdownFeature(&server, {"Import"})); + server.addFeature(new SslFeature(&server)); server.addFeature(new TempFeature(&server, "arangoimp")); server.addFeature(new VersionFeature(&server)); diff --git a/arangosh/Shell/arangosh.cpp b/arangosh/Shell/arangosh.cpp index 9240dbd472..127d415aa8 100644 --- a/arangosh/Shell/arangosh.cpp +++ b/arangosh/Shell/arangosh.cpp @@ -37,6 +37,7 @@ #include "Random/RandomFeature.h" #include "Shell/ShellFeature.h" #include "Shell/V8ShellFeature.h" +#include "Ssl/SslFeature.h" using namespace arangodb; using namespace arangodb::application_features; @@ -62,6 +63,7 @@ int main(int argc, char* argv[]) { server.addFeature(new RandomFeature(&server)); server.addFeature(new ShellFeature(&server, &ret)); server.addFeature(new ShutdownFeature(&server, {"Shell"})); + server.addFeature(new SslFeature(&server)); server.addFeature(new TempFeature(&server, name)); server.addFeature(new V8PlatformFeature(&server)); server.addFeature(new V8ShellFeature(&server, name)); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9a5c12fcaa..124a417430 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -215,6 +215,7 @@ add_library(${LIB_ARANGO} STATIC SimpleHttpClient/SslClientConnection.cpp Ssl/SslFeature.cpp Ssl/SslInterface.cpp + Ssl/SslServerFeature.cpp Ssl/ssl-helper.cpp Utilities/LineEditor.cpp Utilities/ScriptLoader.cpp diff --git a/lib/Ssl/SslFeature.cpp b/lib/Ssl/SslFeature.cpp index b0ef234398..a9821594c3 100644 --- a/lib/Ssl/SslFeature.cpp +++ b/lib/Ssl/SslFeature.cpp @@ -22,9 +22,6 @@ #include "SslFeature.h" -#include -#include - #define OPENSSL_THREAD_DEFINES #include @@ -133,55 +130,12 @@ void opensslCleanup() { } SslFeature::SslFeature(application_features::ApplicationServer* server) - : ApplicationFeature(server, "Ssl"), - _cafile(), - _keyfile(), - _sessionCache(false), - _cipherList(), - _protocol(TLS_V1), - _options( - (long)(SSL_OP_TLS_ROLLBACK_BUG | SSL_OP_CIPHER_SERVER_PREFERENCE)), - _ecdhCurve("prime256v1"), - _sslContext(nullptr) { + : ApplicationFeature(server, "Ssl") { setOptional(true); requiresElevatedPrivileges(false); startsAfter("Logger"); } -void SslFeature::collectOptions(std::shared_ptr options) { - options->addSection("ssl", "Configure SSL communication"); - - options->addOption("--ssl.cafile", "ca file used for secure connections", - new StringParameter(&_cafile)); - - options->addOption("--ssl.keyfile", "key-file used for secure connections", - new StringParameter(&_keyfile)); - - options->addOption("--ssl.session-cache", - "enable the session cache for connections", - new BooleanParameter(&_sessionCache)); - - options->addOption("--ssl.chipher-list", - "ssl chipers to use, see OpenSSL documentation", - new StringParameter(&_cipherList)); - - std::unordered_set sslProtocols = {1, 2, 3, 4}; - - options->addOption("--ssl.protocol", - "ssl protocol (1 = SSLv2, 2 = SSLv23, 3 = SSLv3, 4 = " - "TLSv1, 5 = TLSV1.2 (recommended)", - new UInt64Parameter(&_protocol)); - - options->addHiddenOption( - "--ssl.options", "ssl connection options, see OpenSSL documentation", - new DiscreteValuesParameter(&_options, sslProtocols)); - - options->addOption( - "--ssl.ecdh-curve", - "SSL ECDH Curve, see the output of \"openssl ecparam -list_curves\"", - new StringParameter(&_ecdhCurve)); -} - void SslFeature::prepare() { SSL_library_init(); SSL_load_error_strings(); @@ -189,411 +143,12 @@ void SslFeature::prepare() { ERR_load_crypto_strings(); opensslSetup(); - - createSslContext(); -} - -void SslFeature::start() { - LOG(INFO) << "using SSL options: " << stringifySslOptions(_options); - - if (!_cipherList.empty()) { - LOG(INFO) << "using SSL cipher-list '" << _cipherList << "'"; - } } void SslFeature::stop() { - if (_sslContext != nullptr) { - SSL_CTX_free(_sslContext); - _sslContext = nullptr; - } - opensslCleanup(); ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); } - -namespace { -class BIOGuard { - public: - explicit BIOGuard(BIO* bio) : _bio(bio) {} - - ~BIOGuard() { BIO_free(_bio); } - - public: - BIO* _bio; -}; -} - -void SslFeature::createSslContext() { - // check keyfile - if (_keyfile.empty()) { - return; - } - - // validate protocol - if (_protocol <= SSL_UNKNOWN || _protocol >= SSL_LAST) { - LOG(FATAL) << "invalid SSL protocol version specified. Please use a valid " - "value for '--ssl.protocol.'"; - FATAL_ERROR_EXIT(); - } - - LOG(DEBUG) << "using SSL protocol version '" - << protocolName((protocol_e)_protocol) << "'"; - - if (!FileUtils::exists(_keyfile)) { - LOG(FATAL) << "unable to find SSL keyfile '" << _keyfile << "'"; - FATAL_ERROR_EXIT(); - } - - // create context - _sslContext = ::sslContext(protocol_e(_protocol), _keyfile); - - if (_sslContext == nullptr) { - LOG(FATAL) << "failed to create SSL context, cannot create HTTPS server"; - FATAL_ERROR_EXIT(); - } - - // set cache mode - SSL_CTX_set_session_cache_mode( - _sslContext, _sessionCache ? SSL_SESS_CACHE_SERVER : SSL_SESS_CACHE_OFF); - - if (_sessionCache) { - LOG(TRACE) << "using SSL session caching"; - } - - // set options - SSL_CTX_set_options(_sslContext, (long)_options); - - if (!_cipherList.empty()) { - if (SSL_CTX_set_cipher_list(_sslContext, _cipherList.c_str()) != 1) { - LOG(FATAL) << "cannot set SSL cipher list '" << _cipherList - << "': " << lastSSLError(); - FATAL_ERROR_EXIT(); - } - } - -#if OPENSSL_VERSION_NUMBER >= 0x0090800fL - int sslEcdhNid; - EC_KEY* ecdhKey; - sslEcdhNid = OBJ_sn2nid(_ecdhCurve.c_str()); - - if (sslEcdhNid == 0) { - LOG(FATAL) << "SSL error: " << lastSSLError() - << " Unknown curve name: " << _ecdhCurve; - FATAL_ERROR_EXIT(); - } - - // https://www.openssl.org/docs/manmaster/apps/ecparam.html - ecdhKey = EC_KEY_new_by_curve_name(sslEcdhNid); - if (ecdhKey == nullptr) { - LOG(FATAL) << "SSL error: " << lastSSLError() - << " Unable to create curve by name: " << _ecdhCurve; - FATAL_ERROR_EXIT(); - } - - SSL_CTX_set_tmp_ecdh(_sslContext, ecdhKey); - SSL_CTX_set_options(_sslContext, SSL_OP_SINGLE_ECDH_USE); - EC_KEY_free(ecdhKey); -#endif - - // set ssl context - UniformCharacter r( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); - _rctx = r.random(SSL_MAX_SSL_SESSION_ID_LENGTH); - - int res = SSL_CTX_set_session_id_context( - _sslContext, (unsigned char const*)_rctx.c_str(), (int)_rctx.size()); - - if (res != 1) { - LOG(FATAL) << "cannot set SSL session id context '" << _rctx - << "': " << lastSSLError(); - FATAL_ERROR_EXIT(); - } - - // check CA - if (!_cafile.empty()) { - LOG(TRACE) << "trying to load CA certificates from '" << _cafile << "'"; - - int res = SSL_CTX_load_verify_locations(_sslContext, _cafile.c_str(), 0); - - if (res == 0) { - LOG(FATAL) << "cannot load CA certificates from '" << _cafile - << "': " << lastSSLError(); - FATAL_ERROR_EXIT(); - } - - STACK_OF(X509_NAME) * certNames; - - certNames = SSL_load_client_CA_file(_cafile.c_str()); - - if (certNames == nullptr) { - LOG(FATAL) << "cannot load CA certificates from '" << _cafile - << "': " << lastSSLError(); - FATAL_ERROR_EXIT(); - } - - if (Logger::logLevel() == arangodb::LogLevel::TRACE) { - for (int i = 0; i < sk_X509_NAME_num(certNames); ++i) { - X509_NAME* cert = sk_X509_NAME_value(certNames, i); - - if (cert) { - BIOGuard bout(BIO_new(BIO_s_mem())); - - X509_NAME_print_ex(bout._bio, cert, 0, - (XN_FLAG_SEP_COMMA_PLUS | XN_FLAG_DN_REV | - ASN1_STRFLGS_UTF8_CONVERT) & - ~ASN1_STRFLGS_ESC_MSB); - - char* r; - long len = BIO_get_mem_data(bout._bio, &r); - - LOG(TRACE) << "name: " << std::string(r, len); - } - } - } - - SSL_CTX_set_client_CA_list(_sslContext, certNames); - } -} - -std::string SslFeature::stringifySslOptions( - uint64_t opts) const { - std::string result; - -#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG - if (opts & SSL_OP_MICROSOFT_SESS_ID_BUG) { - result.append(", SSL_OP_MICROSOFT_SESS_ID_BUG"); - } -#endif - -#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG - if (opts & SSL_OP_NETSCAPE_CHALLENGE_BUG) { - result.append(", SSL_OP_NETSCAPE_CHALLENGE_BUG"); - } -#endif - -#ifdef SSL_OP_LEGACY_SERVER_CONNECT - if (opts & SSL_OP_LEGACY_SERVER_CONNECT) { - result.append(", SSL_OP_LEGACY_SERVER_CONNECT"); - } -#endif - -#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG - if (opts & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) { - result.append(", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG"); - } -#endif - -#ifdef SSL_OP_TLSEXT_PADDING - if (opts & SSL_OP_TLSEXT_PADDING) { - result.append(", SSL_OP_TLSEXT_PADDING"); - } -#endif - -#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER - if (opts & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { - result.append(", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER"); - } -#endif - -#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG - if (opts & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) { - result.append(", SSL_OP_SAFARI_ECDHE_ECDSA_BUG"); - } -#endif - -#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG - if (opts & SSL_OP_SSLEAY_080_CLIENT_DH_BUG) { - result.append(", SSL_OP_SSLEAY_080_CLIENT_DH_BUG"); - } -#endif - -#ifdef SSL_OP_TLS_D5_BUG - if (opts & SSL_OP_TLS_D5_BUG) { - result.append(", SSL_OP_TLS_D5_BUG"); - } -#endif - -#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG - if (opts & SSL_OP_TLS_BLOCK_PADDING_BUG) { - result.append(", SSL_OP_TLS_BLOCK_PADDING_BUG"); - } -#endif - -#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING - if (opts & SSL_OP_MSIE_SSLV2_RSA_PADDING) { - result.append(", SSL_OP_MSIE_SSLV2_RSA_PADDING"); - } -#endif - -#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG - if (opts & SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG) { - result.append(", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG"); - } -#endif - -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - if (opts & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) { - result.append(", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"); - } -#endif - -#ifdef SSL_OP_NO_QUERY_MTU - if (opts & SSL_OP_NO_QUERY_MTU) { - result.append(", SSL_OP_NO_QUERY_MTU"); - } -#endif - -#ifdef SSL_OP_COOKIE_EXCHANGE - if (opts & SSL_OP_COOKIE_EXCHANGE) { - result.append(", SSL_OP_COOKIE_EXCHANGE"); - } -#endif - -#ifdef SSL_OP_NO_TICKET - if (opts & SSL_OP_NO_TICKET) { - result.append(", SSL_OP_NO_TICKET"); - } -#endif - -#ifdef SSL_OP_CISCO_ANYCONNECT - if (opts & SSL_OP_CISCO_ANYCONNECT) { - result.append(", SSL_OP_CISCO_ANYCONNECT"); - } -#endif - -#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - if (opts & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) { - result.append(", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"); - } -#endif - -#ifdef SSL_OP_NO_COMPRESSION - if (opts & SSL_OP_NO_COMPRESSION) { - result.append(", SSL_OP_NO_COMPRESSION"); - } -#endif - -#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - if (opts & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) { - result.append(", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"); - } -#endif - -#ifdef SSL_OP_SINGLE_ECDH_USE - if (opts & SSL_OP_SINGLE_ECDH_USE) { - result.append(", SSL_OP_SINGLE_ECDH_USE"); - } -#endif - -#ifdef SSL_OP_SINGLE_DH_USE - if (opts & SSL_OP_SINGLE_DH_USE) { - result.append(", SSL_OP_SINGLE_DH_USE"); - } -#endif - -#ifdef SSL_OP_EPHEMERAL_RSA - if (opts & SSL_OP_EPHEMERAL_RSA) { - result.append(", SSL_OP_EPHEMERAL_RSA"); - } -#endif - -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (opts & SSL_OP_CIPHER_SERVER_PREFERENCE) { - result.append(", SSL_OP_CIPHER_SERVER_PREFERENCE"); - } -#endif - -#ifdef SSL_OP_TLS_ROLLBACK_BUG - if (opts & SSL_OP_TLS_ROLLBACK_BUG) { - result.append(", SSL_OP_TLS_ROLLBACK_BUG"); - } -#endif - -#ifdef SSL_OP_NO_SSLv2 - if (opts & SSL_OP_NO_SSLv2) { - result.append(", SSL_OP_NO_SSLv2"); - } -#endif - -#ifdef SSL_OP_NO_SSLv3 - if (opts & SSL_OP_NO_SSLv3) { - result.append(", SSL_OP_NO_SSLv3"); - } -#endif - -#ifdef SSL_OP_NO_TLSv1 - if (opts & SSL_OP_NO_TLSv1) { - result.append(", SSL_OP_NO_TLSv1"); - } -#endif - -#ifdef SSL_OP_NO_TLSv1_2 - if (opts & SSL_OP_NO_TLSv1_2) { - result.append(", SSL_OP_NO_TLSv1_2"); - } -#endif - -#ifdef SSL_OP_NO_TLSv1_1 - if (opts & SSL_OP_NO_TLSv1_1) { - result.append(", SSL_OP_NO_TLSv1_1"); - } -#endif - -#ifdef SSL_OP_NO_DTLSv1 - if (opts & SSL_OP_NO_DTLSv1) { - result.append(", SSL_OP_NO_DTLSv1"); - } -#endif - -#ifdef SSL_OP_NO_DTLSv1_2 - if (opts & SSL_OP_NO_DTLSv1_2) { - result.append(", SSL_OP_NO_DTLSv1_2"); - } -#endif - -#ifdef SSL_OP_NO_SSL_MASK - if (opts & SSL_OP_NO_SSL_MASK) { - result.append(", SSL_OP_NO_SSL_MASK"); - } -#endif - -#ifdef SSL_OP_PKCS1_CHECK_1 - if (opts & SSL_OP_PKCS1_CHECK_1) { - result.append(", SSL_OP_PKCS1_CHECK_1"); - } -#endif - -#ifdef SSL_OP_PKCS1_CHECK_2 - if (opts & SSL_OP_PKCS1_CHECK_2) { - result.append(", SSL_OP_PKCS1_CHECK_2"); - } -#endif - -#ifdef SSL_OP_NETSCAPE_CA_DN_BUG - if (opts & SSL_OP_NETSCAPE_CA_DN_BUG) { - result.append(", SSL_OP_NETSCAPE_CA_DN_BUG"); - } -#endif - -#ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG - if (opts & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG) { - result.append(", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG"); - } -#endif - -#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG - if (opts & SSL_OP_CRYPTOPRO_TLSEXT_BUG) { - result.append(", SSL_OP_CRYPTOPRO_TLSEXT_BUG"); - } -#endif - - if (result.empty()) { - return result; - } - - // strip initial comma - return result.substr(2); -} diff --git a/lib/Ssl/SslFeature.h b/lib/Ssl/SslFeature.h index df644e77e6..7721ecf60b 100644 --- a/lib/Ssl/SslFeature.h +++ b/lib/Ssl/SslFeature.h @@ -33,30 +33,8 @@ class SslFeature final : public application_features::ApplicationFeature { explicit SslFeature(application_features::ApplicationServer* server); public: - void collectOptions(std::shared_ptr) override final; void prepare() override final; - void start() override final; void stop() override final; - - public: - SSL_CTX* sslContext() const { return _sslContext; } - - public: - std::string _cafile; - std::string _keyfile; - bool _sessionCache; - std::string _cipherList; - uint64_t _protocol; - uint64_t _options; - std::string _ecdhCurve; - - private: - void createSslContext(); - std::string stringifySslOptions(uint64_t opts) const; - - private: - SSL_CTX* _sslContext; - std::string _rctx; }; } diff --git a/lib/Ssl/ssl-helper.h b/lib/Ssl/ssl-helper.h index 12f87acf08..6a861f7cb4 100644 --- a/lib/Ssl/ssl-helper.h +++ b/lib/Ssl/ssl-helper.h @@ -27,6 +27,7 @@ #include "Basics/Common.h" #include +#include namespace arangodb {