diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index 2834e41702..37acbec984 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -2802,6 +2802,18 @@ MySqlHostDataSourceImpl::createContext() const { // Open the database. ctx->conn_.openDatabase(); + // Check if we have TLS when we required it. + if (ctx->conn_.getTls()) { + std::string cipher = ctx->conn_.getTlsCipher(); + if (cipher.empty()) { + LOG_ERROR(dhcpsrv_logger, DHCPSRV_MYSQL_NO_TLS); + } else { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, + DHCPSRV_MYSQL_TLS_CIPHER) + .arg(cipher); + } + } + // Prepare query statements. Those are will be only used to retrieve // information from the database, so they can be used even if the // database is read only for the current user. diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index f7668540ea..c97740bbe3 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -1887,6 +1887,18 @@ MySqlLeaseMgr::createContext() const { // Open the database. ctx->conn_.openDatabase(); + // Check if we have TLS when we required it. + if (ctx->conn_.getTls()) { + std::string cipher = ctx->conn_.getTlsCipher(); + if (cipher.empty()) { + LOG_ERROR(dhcpsrv_logger, DHCPSRV_MYSQL_NO_TLS); + } else { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, + DHCPSRV_MYSQL_TLS_CIPHER) + .arg(cipher); + } + } + // Prepare all statements likely to be used. ctx->conn_.prepareStatements(tagged_statements.begin(), tagged_statements.end()); diff --git a/src/lib/mysql/mysql_connection.cc b/src/lib/mysql/mysql_connection.cc index 0ef5f37ec8..672a3bcc58 100644 --- a/src/lib/mysql/mysql_connection.cc +++ b/src/lib/mysql/mysql_connection.cc @@ -16,6 +16,21 @@ #include #include #include +#include + +namespace { // anonymous namespace + +// C++17 has this function but Kea is still C++11 so provide it. +bool +isDir(const std::string& name) { + struct stat stats; + if (::stat(name.c_str(), &stats) < 0) { + return (false); + } + return ((stats.st_mode & S_IFMT) == S_IFDIR); +} + +} // end of namespace using namespace isc; using namespace std; @@ -49,7 +64,6 @@ MySqlTransaction::commit() { committed_ = true; } - // Open the database using the parameters passed to the constructor. void @@ -156,6 +170,51 @@ MySqlConnection::openDatabase() { } } + const char* ca_file(0); + const char* ca_dir(0); + string sca; + try { + sca = getParameter("trust-anchor"); + tls_ = true; + if (isDir(sca)) { + ca_dir = sca.c_str(); + } else { + ca_file = sca.c_str(); + } + } catch (...) { + // No trust anchor + } + + const char* cert_file(0); + string scert; + try { + scert = getParameter("cert-file"); + tls_ = true; + cert_file = scert.c_str(); + } catch (...) { + // No client certificate file + } + + const char* key_file(0); + string skey; + try { + skey = getParameter("key-file"); + tls_ = true; + key_file = skey.c_str(); + } catch (...) { + // No private key file + } + + const char* cipher_list(0); + string scipher; + try { + scipher = getParameter("cipher-list"); + tls_ = true; + cipher_list = scipher.c_str(); + } catch (...) { + // No cipher list + } + // Set options for the connection: // // Set options for the connection: @@ -196,6 +255,13 @@ MySqlConnection::openDatabase() { mysql_error(mysql_)); } + // If TLS is enabled set it. If something should go wrong it will be later + // at the mysql_real_connect call. + if (tls_) { + mysql_ssl_set(mysql_, key_file, cert_file, ca_file, ca_dir, + cipher_list); + } + // Open the database. // // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE, diff --git a/src/lib/mysql/mysql_connection.h b/src/lib/mysql/mysql_connection.h index 767e385e1e..bac7220530 100644 --- a/src/lib/mysql/mysql_connection.h +++ b/src/lib/mysql/mysql_connection.h @@ -250,7 +250,7 @@ public: DbCallback callback = DbCallback()) : DatabaseConnection(parameters, callback), io_service_accessor_(io_accessor), io_service_(), - transaction_ref_count_(0) { + transaction_ref_count_(0), tls_(false) { } /// @brief Destructor @@ -697,6 +697,21 @@ public: } } + /// @brief Get the TLS flag. + /// + /// @return True if TLS was required, false otherwise. + bool getTls() const { + return (tls_); + } + + /// @brief Get the TLS cipher + /// + /// This method is used to check if required TLS was setup. + std::string getTlsCipher() { + const char* cipher = mysql_get_ssl_cipher(mysql_); + return (cipher ? std::string(cipher) : ""); + } + /// @brief Prepared statements /// /// This field is public, because it is used heavily from MySqlConnection @@ -734,6 +749,9 @@ public: /// started. We want to not start new transactions when one is already /// in progress. int transaction_ref_count_; + + /// @brief TLS flag (true when TLS was required, false otherwise). + bool tls_; }; } // end of isc::db namespace