str<<base<<"tcpcurrentconnections" << ' '<< front->tcpCurrentConnections.load() << " " << now << "\r\n";
str<<base<<"tcpavgqueriesperconnection" << ' '<< front->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
str<<base<<"tcpavgconnectionduration" << ' '<< front->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
- str<<base<<"tlsnewsessions" << ' ' << front->tlsNewSessions.load() << " " << now << "\r\n";
- str<<base<<"tlsresumptions" << ' ' << front->tlsResumptions.load() << " " << now << "\r\n";
str<<base<<"tls10-queries" << ' ' << front->tls10queries.load() << " " << now << "\r\n";
str<<base<<"tls11-queries" << ' ' << front->tls11queries.load() << " " << now << "\r\n";
str<<base<<"tls12-queries" << ' ' << front->tls12queries.load() << " " << now << "\r\n";
str<<base<<"tls13-queries" << ' ' << front->tls13queries.load() << " " << now << "\r\n";
str<<base<<"tls-unknown-queries" << ' ' << front->tlsUnknownqueries.load() << " " << now << "\r\n";
+ str<<base<<"tlsnewsessions" << ' ' << front->tlsNewSessions.load() << " " << now << "\r\n";
+ str<<base<<"tlsresumptions" << ' ' << front->tlsResumptions.load() << " " << now << "\r\n";
+ str<<base<<"tlsunknownticketkeys" << ' ' << front->tlsUnknownTicketKey.load() << " " << now << "\r\n";
+ str<<base<<"tlsinactiveticketkeys" << ' ' << front->tlsInactiveTicketKey.load() << " " << now << "\r\n";
}
auto localPools = g_pools.getLocal();
ret << endl;
ret << "Frontends:" << endl;
- fmt = boost::format("%-3d %-20.20s %-20d %-20d %-25d %-20d %-20d %-20d %-20f %-20f %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
- ret << (fmt % "#" % "Address" % "Connections" % "Died reading query" % "Died sending response" % "Gave up" % "Client timeouts" % "Downstream timeouts" % "Avg queries/conn" % "Avg duration" % "TLS new sessions" % "TLS Resumptions" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other") << endl;
+ fmt = boost::format("%-3d %-20.20s %-20d %-20d %-25d %-20d %-20d %-20d %-20f %-20f %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "Connections" % "Died reading query" % "Died sending response" % "Gave up" % "Client timeouts" % "Downstream timeouts" % "Avg queries/conn" % "Avg duration" % "TLS new sessions" % "TLS Resumptions" % "TLS unknown ticket keys" % "TLS inactive ticket keys" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other") << endl;
size_t counter = 0;
for(const auto& f : g_frontends) {
- ret << (fmt % counter % f->local.toStringWithPort() % f->tcpCurrentConnections % f->tcpDiedReadingQuery % f->tcpDiedSendingResponse % f->tcpGaveUp % f->tcpClientTimeouts % f->tcpDownstreamTimeouts % f->tcpAvgQueriesPerConnection % f->tcpAvgConnectionDuration % f->tlsNewSessions % f->tlsResumptions % f->tls10queries % f->tls11queries % f->tls12queries % f->tls13queries % f->tlsUnknownqueries) << endl;
+ ret << (fmt % counter % f->local.toStringWithPort() % f->tcpCurrentConnections % f->tcpDiedReadingQuery % f->tcpDiedSendingResponse % f->tcpGaveUp % f->tcpClientTimeouts % f->tcpDownstreamTimeouts % f->tcpAvgQueriesPerConnection % f->tcpAvgConnectionDuration % f->tlsNewSessions % f->tlsResumptions % f->tlsUnknownTicketKey % f->tlsInactiveTicketKey % f->tls10queries % f->tls11queries % f->tls12queries % f->tls13queries % f->tlsUnknownqueries) << endl;
++counter;
}
ret << endl;
setLuaNoSideEffect();
try {
ostringstream ret;
- boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
- ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "GET" % "POST" % "Bad" % "Errors" % "Redirects" % "Valid") << endl;
+ boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "GET" % "POST" % "Bad" % "Errors" % "Redirects" % "Valid" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
size_t counter = 0;
for (const auto& ctx : g_dohlocals) {
- ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http1Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses) << endl;
+ ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http1Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->d_ticketsKeyRotationDelay % ctx->getNextTicketsKeyRotation()) << endl;
counter++;
}
g_outputBuffer = ret.str();
else {
++state->d_ci.cs->tlsResumptions;
}
+ if (state->d_handler.getResumedFromInactiveTicketKey()) {
+ ++state->d_ci.cs->tlsInactiveTicketKey;
+ }
+ if (state->d_handler.getUnknownTicketKey()) {
+ ++state->d_ci.cs->tlsUnknownTicketKey;
+ }
}
state->d_handshakeDoneTime = now;
output << "# TYPE " << frontsbase << "tcpavgqueriesperconnection " << "gauge" << "\n";
output << "# HELP " << frontsbase << "tcpavgconnectionduration " << "The average duration of a TCP connection (ms)" << "\n";
output << "# TYPE " << frontsbase << "tcpavgconnectionduration " << "gauge" << "\n";
+ output << "# HELP " << frontsbase << "tlsqueries " << "Number of queries received by dnsdist over TLS, by TLS version" << "\n";
+ output << "# TYPE " << frontsbase << "tlsqueries " << "counter" << "\n";
output << "# HELP " << frontsbase << "tlsnewsessions " << "Amount of new TLS sessions negotiated" << "\n";
output << "# TYPE " << frontsbase << "tlsnewsessions " << "counter" << "\n";
output << "# HELP " << frontsbase << "tlsresumptions " << "Amount of TLS sessions resumed" << "\n";
output << "# TYPE " << frontsbase << "tlsresumptions " << "counter" << "\n";
- output << "# HELP " << frontsbase << "tlsqueries " << "Number of queries received by dnsdist over TLS, by TLS version" << "\n";
- output << "# TYPE " << frontsbase << "tlsqueries " << "counter" << "\n";
+ output << "# HELP " << frontsbase << "tlsunknownticketkeys " << "Amount of attempts to resume TLS session from an unknown key (possibly expired)" << "\n";
+ output << "# TYPE " << frontsbase << "tlsunknownticketkeys " << "counter" << "\n";
+ output << "# HELP " << frontsbase << "tlsinactiveticketkeys " << "Amount of TLS sessions resumed from an inactive key" << "\n";
+ output << "# TYPE " << frontsbase << "tlsinactiveticketkeys " << "counter" << "\n";
std::map<std::string,uint64_t> frontendDuplicates;
for (const auto& front : g_frontends) {
output << frontsbase << "tcpavgconnectionduration" << label << front->tcpAvgConnectionDuration.load() << "\n";
output << frontsbase << "tlsnewsessions" << label << front->tlsNewSessions.load() << "\n";
output << frontsbase << "tlsresumptions" << label << front->tlsResumptions.load() << "\n";
+ output << frontsbase << "tlsunknownticketkeys" << label << front->tlsUnknownTicketKey.load() << "\n";
+ output << frontsbase << "tlsinactiveticketkeys" << label << front->tlsInactiveTicketKey.load() << "\n";
output << frontsbase << "tlsqueries{frontend=\"" << frontName << "\",proto=\"" << proto << "\",tls=\"tls10\"} " << front->tls10queries.load() << "\n";
output << frontsbase << "tlsqueries{frontend=\"" << frontName << "\",proto=\"" << proto << "\",tls=\"tls11\"} " << front->tls11queries.load() << "\n";
{ "tcpAvgConnectionDuration", (double) front->tcpAvgConnectionDuration },
{ "tlsNewSessions", (double) front->tlsNewSessions },
{ "tlsResumptions", (double) front->tlsResumptions },
+ { "tlsUnknownTicketKey", (double) front->tlsUnknownTicketKey },
+ { "tlsInactiveTicketKey", (double) front->tlsInactiveTicketKey },
{ "tls10Queries", (double) front->tls10queries },
{ "tls11Queries", (double) front->tls11queries },
{ "tls12Queries", (double) front->tls12queries },
std::atomic<uint64_t> tcpCurrentConnections{0};
std::atomic<uint64_t> tlsNewSessions{0}; // A new TLS session has been negotiated, no resumption
std::atomic<uint64_t> tlsResumptions{0}; // A TLS session has been resumed, either via session id or via a TLS ticket
+ std::atomic<uint64_t> tlsUnknownTicketKey{0}; // A TLS ticket has been presented but we don't have the associated key (might have expired)
+ std::atomic<uint64_t> tlsInactiveTicketKey{0}; // A TLS ticket has been successfully resumed but the key is no longer active, we should issue a new one
std::atomic<uint64_t> tls10queries{0}; // valid DNS queries received via TLSv1.0
std::atomic<uint64_t> tls11queries{0}; // valid DNS queries received via TLSv1.1
std::atomic<uint64_t> tls12queries{0}; // valid DNS queries received via TLSv1.2
std::atomic<uint64_t> tls13queries{0}; // valid DNS queries received via TLSv1.3
std::atomic<uint64_t> tlsUnknownqueries{0}; // valid DNS queries received via unknown TLS version
-
std::atomic<double> tcpAvgQueriesPerConnection{0.0};
/* in ms */
std::atomic<double> tcpAvgConnectionDuration{0.0};
df->handleTicketsKeyRotation();
- return libssl_ticket_key_callback(s, *df->d_ticketKeys, keyName, iv, ectx, hctx, enc);
+ auto ret = libssl_ticket_key_callback(s, *df->d_ticketKeys, keyName, iv, ectx, hctx, enc);
+ if (enc == 0) {
+ if (ret == 0) {
+ ++df->d_dsc->cs->tlsUnknownTicketKey;
+ }
+ else if (ret == 2) {
+ ++df->d_dsc->cs->tlsInactiveTicketKey;
+ }
+ }
+
+ return ret;
}
static std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> getTLSContext(DOHFrontend& df,
{
d_socket = socket;
+ if (!s_initTLSConnIndex.test_and_set()) {
+ /* not initialized yet */
+ s_tlsConnIndex = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+ if (s_tlsConnIndex == -1) {
+ throw std::runtime_error("Error getting an index for TLS connection data");
+ }
+ }
+
if (!d_conn) {
vinfolog("Error creating TLS object");
if (g_verbose) {
if (!SSL_set_fd(d_conn.get(), d_socket)) {
throw std::runtime_error("Error assigning socket");
}
+
+ SSL_set_ex_data(d_conn.get(), s_tlsConnIndex, this);
}
IOState convertIORequestToIOState(int res) const
return false;
}
+ static int s_tlsConnIndex;
private:
+ static std::atomic_flag s_initTLSConnIndex;
+
std::unique_ptr<SSL, void(*)(SSL*)> d_conn;
unsigned int d_timeout;
};
+std::atomic_flag OpenSSLTLSConnection::s_initTLSConnIndex = ATOMIC_FLAG_INIT;
+int OpenSSLTLSConnection::s_tlsConnIndex = -1;
+
class OpenSSLTLSIOCtx: public TLSCtx
{
public:
return -1;
}
- return libssl_ticket_key_callback(s, ctx->d_ticketKeys, keyName, iv, ectx, hctx, enc);
+ int ret = libssl_ticket_key_callback(s, ctx->d_ticketKeys, keyName, iv, ectx, hctx, enc);
+ if (enc == 0) {
+ if (ret == 0 || ret == 2) {
+ OpenSSLTLSConnection* conn = reinterpret_cast<OpenSSLTLSConnection*>(SSL_get_ex_data(s, OpenSSLTLSConnection::s_tlsConnIndex));
+ if (conn) {
+ if (ret == 0) {
+ conn->setUnknownTicketKey();
+ }
+ else if (ret == 2) {
+ conn->setResumedFromInactiveTicketKey();
+ }
+ }
+ }
+ }
+
+ return ret;
}
static int ocspStaplingCb(SSL* ssl, void* arg)
#endif /* HAVE_DNS_OVER_HTTPS */
+ time_t getNextTicketsKeyRotation() const
+ {
+ return d_ticketsKeyNextRotation;
+ }
+
+ size_t getTicketsKeysCount() const
+ {
+ size_t res = 0;
+#ifdef HAVE_DNS_OVER_HTTPS
+ if (d_ticketKeys) {
+ res = d_ticketKeys->getKeysCount();
+ }
+#endif /* HAVE_DNS_OVER_HTTPS */
+ return res;
+ }
+
private:
time_t d_ticketsKeyNextRotation{0};
std::atomic_flag d_rotatingTicketsKey;
virtual bool hasSessionBeenResumed() const = 0;
virtual void close() = 0;
+ void setUnknownTicketKey()
+ {
+ d_unknownTicketKey = true;
+ }
+
+ bool getUnknownTicketKey() const
+ {
+ return d_unknownTicketKey;
+ }
+
+ void setResumedFromInactiveTicketKey()
+ {
+ d_resumedFromInactiveTicketKey = true;
+ }
+
+ bool getResumedFromInactiveTicketKey() const
+ {
+ return d_resumedFromInactiveTicketKey;
+ }
+
protected:
int d_socket{-1};
+ bool d_unknownTicketKey{false};
+ bool d_resumedFromInactiveTicketKey{false};
};
class TLSCtx
return d_conn && d_conn->hasSessionBeenResumed();
}
+ bool getResumedFromInactiveTicketKey() const
+ {
+ return d_conn && d_conn->getResumedFromInactiveTicketKey();
+ }
+
+ bool getUnknownTicketKey() const
+ {
+ return d_conn && d_conn->getUnknownTicketKey();
+ }
+
private:
std::unique_ptr<TLSConnection> d_conn{nullptr};
int d_socket{-1};