Skip to content

Commit

Permalink
dnsdist: add support for a callback when a new tickets key is added t…
Browse files Browse the repository at this point in the history
…o the tls context
  • Loading branch information
chbruyand committed Jun 27, 2024
1 parent 419829f commit 3cf627a
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 1 deletion.
5 changes: 5 additions & 0 deletions pdns/dnsdistdist/dnsdist-doh-common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ void DOHFrontend::rotateTicketsKey(time_t now)
return d_tlsContext.rotateTicketsKey(now);
}

void DOHFrontend::setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook)
{
return d_tlsContext.setTicketsKeyAddedHook(hook);
}

void DOHFrontend::loadTicketsKeys(const std::string& keyFile)
{
return d_tlsContext.loadTicketsKeys(keyFile);
Expand Down
5 changes: 5 additions & 0 deletions pdns/dnsdistdist/dnsdist-doh-common.hh
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ struct DOHFrontend
{
}

virtual void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& /* hook */)
{
}

virtual void loadTicketsKeys(const std::string& /* keyFile */)
{
}
Expand All @@ -185,6 +189,7 @@ struct DOHFrontend
virtual void setup();
virtual void reloadCertificates();

virtual void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook);
virtual void rotateTicketsKey(time_t now);
virtual void loadTicketsKeys(const std::string& keyFile);
virtual void handleTicketsKeyRotation();
Expand Down
23 changes: 23 additions & 0 deletions pdns/dnsdistdist/dnsdist-lua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3011,6 +3011,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
});


luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(const dnsdist_tickets_key_added_hook&)>("setTicketsKeyAddedHook", [](const std::shared_ptr<DOHFrontend>& frontend, const dnsdist_tickets_key_added_hook& hook) {
if (frontend != nullptr) {
frontend->setTicketsKeyAddedHook(hook);
}
});

luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(const LuaArray<std::shared_ptr<DOHResponseMapEntry>>&)>("setResponsesMap", [](const std::shared_ptr<DOHFrontend>& frontend, const LuaArray<std::shared_ptr<DOHResponseMapEntry>>& map) {
if (frontend != nullptr) {
auto newMap = std::make_shared<std::vector<std::shared_ptr<DOHResponseMapEntry>>>();
Expand Down Expand Up @@ -3208,6 +3215,12 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
});

luaCtx.registerFunction<void (std::shared_ptr<TLSCtx>::*)(const dnsdist_tickets_key_added_hook&)>("setTicketsKeyAddedHook", [](const std::shared_ptr<TLSCtx>& frontend, const dnsdist_tickets_key_added_hook& hook) {
if (frontend != nullptr) {
frontend->setTicketsKeyAddedHook(hook);
}
});

luaCtx.registerFunction<void (std::shared_ptr<TLSCtx>::*)(const std::string&)>("loadTicketsKeys", [](std::shared_ptr<TLSCtx>& ctx, const std::string& file) {
if (ctx != nullptr) {
ctx->loadTicketsKeys(file);
Expand All @@ -3221,6 +3234,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
return frontend->d_addr.toStringWithPort();
});

luaCtx.registerFunction<void (std::shared_ptr<TLSFrontend>::*)(const dnsdist_tickets_key_added_hook&)>("setTicketsKeyAddedHook", [](const std::shared_ptr<TLSFrontend>& frontend, const dnsdist_tickets_key_added_hook& hook) {
if (frontend == nullptr) {
return;
}
auto ctx = frontend->getContext();
if (ctx) {
ctx->setTicketsKeyAddedHook(hook);
}
});

luaCtx.registerFunction<void (std::shared_ptr<TLSFrontend>::*)()>("rotateTicketsKey", [](std::shared_ptr<TLSFrontend>& frontend) {
if (frontend == nullptr) {
return;
Expand Down
33 changes: 33 additions & 0 deletions pdns/dnsdistdist/docs/reference/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2322,6 +2322,17 @@ DOHFrontend

Replace the current TLS tickets key by a new random one.

.. method:: DOHFrontend:setTicketsKeyAddedHook(callback)

.. versionadded:: 1.9.0

Set a Lua function that will be called everytime a new tickets key is added. The function receives:

* the key content as a string
* the keylen as an integer

See :doc:`../advanced/tls-sessions-management` for more information.

.. method:: DOHFrontend:setResponsesMap(rules)

Set a list of HTTP response rules allowing to intercept HTTP queries very early, before the DNS payload has been processed, and send custom responses including error pages, redirects and static content.
Expand Down Expand Up @@ -2464,6 +2475,17 @@ TLSContext

Replace the current TLS tickets key by a new random one.

.. method:: TLSContext:setTicketsKeyAddedHook(callback)

.. versionadded:: 1.9.0

Set a Lua function that will be called everytime a new tickets key is added. The function receives:

* the key content as a string
* the keylen as an integer

See :doc:`../advanced/tls-sessions-management` for more information.

TLSFrontend
~~~~~~~~~~~

Expand Down Expand Up @@ -2505,6 +2527,17 @@ TLSFrontend

Replace the current TLS tickets key by a new random one.

.. method:: TLSFrontend:setTicketsKeyAddedHook(callback)

.. versionadded:: 1.9.0

Set a Lua function that will be called everytime a new tickets key is added. The function receives:

* the key content as a string
* the keylen as an integer

See :doc:`../advanced/tls-sessions-management` for more information.

EDNS on Self-generated answers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
21 changes: 21 additions & 0 deletions pdns/libssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,16 @@ OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing() = default;
void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey)
{
d_ticketKeys.write_lock()->push_front(std::move(newKey));
if (d_ticketsKeyAddedHook) {
auto key = d_ticketKeys.read_lock()->front();
auto keyContent = key->content();
d_ticketsKeyAddedHook(keyContent.c_str(), keyContent.size());
}
}

void OpenSSLTLSTicketKeysRing::setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook)
{
d_ticketsKeyAddedHook = hook;
}

std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey()
Expand Down Expand Up @@ -737,6 +747,17 @@ bool OpenSSLTLSTicketKey::nameMatches(const unsigned char name[TLS_TICKETS_KEY_N
return (memcmp(d_name, name, sizeof(d_name)) == 0);
}

std::string OpenSSLTLSTicketKey::content() const
{
std::string result{};
result.reserve(TLS_TICKETS_KEY_NAME_SIZE + TLS_TICKETS_CIPHER_KEY_SIZE + TLS_TICKETS_MAC_KEY_SIZE);
result.append(reinterpret_cast<const char*>(d_name), TLS_TICKETS_KEY_NAME_SIZE);
result.append(reinterpret_cast<const char*>(d_cipherKey), TLS_TICKETS_CIPHER_KEY_SIZE);
result.append(reinterpret_cast<const char*>(d_hmacKey), TLS_TICKETS_MAC_KEY_SIZE);

return result;
}

#if OPENSSL_VERSION_MAJOR >= 3
static const std::string sha256KeyName{"sha256"};
#endif
Expand Down
6 changes: 5 additions & 1 deletion pdns/libssl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public:
#if OPENSSL_VERSION_MAJOR >= 3
int encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx) const;
bool decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx) const;
std::string content() const;
#else
int encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const;
bool decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const;
Expand All @@ -111,6 +112,8 @@ private:
unsigned char d_hmacKey[TLS_TICKETS_MAC_KEY_SIZE];
};

using dnsdist_tickets_key_added_hook = std::function<void(const char* key, size_t keyLen)>;

class OpenSSLTLSTicketKeysRing
{
public:
Expand All @@ -121,10 +124,11 @@ public:
size_t getKeysCount();
void loadTicketsKeys(const std::string& keyFile);
void rotateTicketsKey(time_t now);
void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook);

private:
void addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey);

dnsdist_tickets_key_added_hook d_ticketsKeyAddedHook;
SharedLockGuarded<boost::circular_buffer<std::shared_ptr<OpenSSLTLSTicketKey> > > d_ticketKeys;
};

Expand Down
25 changes: 25 additions & 0 deletions pdns/tcpiohandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,11 @@ class OpenSSLTLSIOCtx: public TLSCtx
}
}

void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook) override
{
d_feContext->d_ticketKeys.setTicketsKeyAddedHook(hook);
}

void loadTicketsKeys(const std::string& keyFile) final
{
d_feContext->d_ticketKeys.loadTicketsKeys(keyFile);
Expand Down Expand Up @@ -987,6 +992,14 @@ class GnuTLSTicketsKey
throw;
}
}
std::string content() const
{
std::string result{};
if (d_key.data != nullptr && d_key.size > 0) {
result.append(reinterpret_cast<const char*>(d_key.data), d_key.size);
}
return result;
}

~GnuTLSTicketsKey()
{
Expand Down Expand Up @@ -1730,6 +1743,11 @@ class GnuTLSIOCtx: public TLSCtx
return connection;
}

void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook) override
{
d_ticketsKeyAddedHook = hook;
}

void rotateTicketsKey(time_t now) override
{
if (!d_enableTickets) {
Expand All @@ -1745,6 +1763,12 @@ class GnuTLSIOCtx: public TLSCtx
if (d_ticketsKeyRotationDelay > 0) {
d_ticketsKeyNextRotation = now + d_ticketsKeyRotationDelay;
}

if (d_ticketsKeyAddedHook) {
auto ticketsKey = *(d_ticketsKey.read_lock());
auto content = ticketsKey->content();
d_ticketsKeyAddedHook(content.c_str(), content.size());
}
}

void loadTicketsKeys(const std::string& file) final
Expand Down Expand Up @@ -1792,6 +1816,7 @@ class GnuTLSIOCtx: public TLSCtx
SharedLockGuarded<std::shared_ptr<GnuTLSTicketsKey>> d_ticketsKey{nullptr};
bool d_enableTickets{true};
bool d_validateCerts{true};
dnsdist_tickets_key_added_hook d_ticketsKeyAddedHook;
};

#endif /* HAVE_GNUTLS */
Expand Down
11 changes: 11 additions & 0 deletions pdns/tcpiohandler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ public:
{
throw std::runtime_error("This TLS backend does not have the capability to load a tickets key from a file");
}
virtual void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& /* hook */)
{
throw std::runtime_error("This TLS backend does not have the capability to setup a hook for added tickets keys");
}

void handleTicketsKeyRotation(time_t now)
{
Expand Down Expand Up @@ -152,6 +156,13 @@ public:
}
}

void setTicketsKeyAddedHook(const dnsdist_tickets_key_added_hook& hook)
{
if (d_ctx != nullptr) {
d_ctx->setTicketsKeyAddedHook(hook);
}
}

void loadTicketsKeys(const std::string& file)
{
if (d_ctx != nullptr) {
Expand Down
37 changes: 37 additions & 0 deletions regression-tests.dnsdist/test_TLS.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,3 +516,40 @@ def setUpClass(cls):
cls.startResponders()
cls.startDNSDist()
cls.setUpSockets()

class TestTLSTicketsKeyAddedCallback(DNSDistTest):
_consoleKey = DNSDistTest.generateConsoleKey()
_consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')

_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
_tlsServerPort = pickAvailablePort()
_numberOfKeys = 5

_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
_config_template = """
setKey("%s")
controlSocket("127.0.0.1:%s")
newServer{address="127.0.0.1:%s"}
addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="openssl" })
callbackCalled = 0
function keyAddedCallback(key, keyLen)
callbackCalled = keyLen
end
"""

def testLuaThreadCounter(self):
"""
LuaThread: Test the lua newThread interface
"""
self.sendConsoleCommand('getTLSFrontend(0):setTicketsKeyAddedHook(keyAddedCallback)');
called = self.sendConsoleCommand('callbackCalled')
self.assertEqual(int(called), 0)
self.sendConsoleCommand("getTLSFrontend(0):rotateTicketsKey()")
called = self.sendConsoleCommand('callbackCalled')
self.assertGreater(int(called), 0)

0 comments on commit 3cf627a

Please sign in to comment.