* `printDNSCryptProviderFingerprint("/path/to/providerPublic.key")`: display the fingerprint of the provided resolver public key
* `showDNSCryptBinds():`: display the currently configured DNSCrypt binds
* RemoteLogger related:
- * `newRemoteLogger(address:port)`: create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()`
+ * `newRemoteLogger(address:port [, timeout=2, maxQueuedEntries=100, reconnectWaitTime=1])`: create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()`
All hooks
---------
g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLogger> logger) {
return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger));
});
- g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote) {
- return std::make_shared<RemoteLogger>(ComboAddress(remote));
+ g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
+ return std::make_shared<RemoteLogger>(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1);
});
}
--- /dev/null
+
+#include "config.h"
+
+#include "dnsdist.hh"
+
+#include "dnsparser.hh"
+#include "dnsdist-protobuf.hh"
+
+#ifdef HAVE_PROTOBUF
+#include "dnsmessage.pb.h"
+
+static void protobufFillMessage(PBDNSMessage& message, const DNSQuestion& dq)
+{
+ std::string* messageId = message.mutable_messageid();
+ messageId->resize(dq.uniqueId.size());
+ std::copy(dq.uniqueId.begin(), dq.uniqueId.end(), messageId->begin());
+
+ message.set_socketfamily(dq.remote->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
+ message.set_socketprotocol(dq.tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
+ if (dq.local->sin4.sin_family == AF_INET) {
+ message.set_to(&dq.local->sin4.sin_addr.s_addr, sizeof(dq.local->sin4.sin_addr.s_addr));
+ }
+ else if (dq.local->sin4.sin_family == AF_INET6) {
+ message.set_to(&dq.local->sin6.sin6_addr.s6_addr, sizeof(dq.local->sin6.sin6_addr.s6_addr));
+ }
+ if (dq.remote->sin4.sin_family == AF_INET) {
+ message.set_from(&dq.remote->sin4.sin_addr.s_addr, sizeof(dq.remote->sin4.sin_addr.s_addr));
+ }
+ else if (dq.remote->sin4.sin_family == AF_INET6) {
+ message.set_from(&dq.remote->sin6.sin6_addr.s6_addr, sizeof(dq.remote->sin6.sin6_addr.s6_addr));
+ }
+
+ message.set_inbytes(dq.len);
+
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ message.set_timesec(ts.tv_sec);
+ message.set_timeusec(ts.tv_nsec / 1000);
+ message.set_id(ntohs(dq.dh->id));
+
+ PBDNSMessage_DNSQuestion* question = message.mutable_question();
+ question->set_qname(dq.qname->toString());
+ question->set_qtype(dq.qtype);
+ question->set_qclass(dq.qclass);
+}
+
+void protobufMessageFromQuestion(const DNSQuestion& dq, std::string& data)
+{
+ PBDNSMessage message;
+ message.set_type(PBDNSMessage_Type_DNSQueryType);
+ protobufFillMessage(message, dq);
+// cerr <<message.DebugString()<<endl;
+ message.SerializeToString(&data);
+}
+
+static void addRRs(const char* packet, const size_t len, PBDNSMessage_DNSResponse& response)
+{
+ if (len < sizeof(struct dnsheader))
+ return;
+
+ const struct dnsheader* dh = (const struct dnsheader*) packet;
+
+ if (ntohs(dh->ancount) == 0)
+ return;
+
+ if (ntohs(dh->qdcount) == 0)
+ return;
+
+ vector<uint8_t> content(len - sizeof(dnsheader));
+ copy(packet + sizeof(dnsheader), packet + len, content.begin());
+ PacketReader pr(content);
+
+ size_t idx = 0;
+ DNSName rrname;
+ uint16_t qdcount = ntohs(dh->qdcount);
+ uint16_t ancount = ntohs(dh->ancount);
+ uint16_t rrtype;
+ uint16_t rrclass;
+ string blob;
+ struct dnsrecordheader ah;
+
+ rrname = pr.getName();
+ rrtype = pr.get16BitInt();
+ rrclass = pr.get16BitInt();
+
+ /* consume remaining qd if any */
+ if (qdcount > 1) {
+ for(idx = 1; idx < qdcount; idx++) {
+ rrname = pr.getName();
+ rrtype = pr.get16BitInt();
+ rrclass = pr.get16BitInt();
+ (void) rrtype;
+ (void) rrclass;
+ }
+ }
+
+ /* parse AN */
+ for (idx = 0; idx < ancount; idx++) {
+ rrname = pr.getName();
+ pr.getDnsrecordheader(ah);
+
+ pr.xfrBlob(blob);
+
+ if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
+ PBDNSMessage_DNSResponse_DNSRR* rr = response.add_rrs();
+ if (rr) {
+ rr->set_name(rrname.toString());
+ rr->set_type(ah.d_type);
+ rr->set_class_(ah.d_class);
+ rr->set_ttl(ah.d_ttl);
+ rr->set_rdata(blob.c_str(), blob.length());
+ }
+ }
+ }
+}
+
+void protobufMessageFromResponse(const DNSQuestion& dr, std::string& data)
+{
+ PBDNSMessage message;
+ message.set_type(PBDNSMessage_Type_DNSResponseType);
+ protobufFillMessage(message, dr);
+
+ PBDNSMessage_DNSResponse response;
+ response.set_rcode(dr.dh->rcode);
+ addRRs((const char*) dr.dh, dr.len, response);
+ message.set_allocated_response(&response);
+
+// cerr <<message.DebugString()<<endl;
+ message.SerializeToString(&data);
+ message.release_response();
+}
+#endif /* HAVE_PROTOBUF */
--- /dev/null
+
+#pragma once
+#include "config.h"
+
+#ifdef HAVE_PROTOBUF
+void protobufMessageFromQuestion(const DNSQuestion& dq, std::string& data);
+void protobufMessageFromResponse(const DNSQuestion& dr, std::string& data);
+
+#endif /* HAVE_PROTOBUF */
+++ /dev/null
-
-#include "dolog.hh"
-#include "dnsdist.hh"
-#include "dnsdist-remotelogger.hh"
-#include "dnsparser.hh"
-
-#ifdef HAVE_PROTOBUF
-#include <boost/uuid/uuid_io.hpp>
-#include "dnsmessage.pb.h"
-#endif
-
-bool RemoteLogger::reconnect()
-{
- if (d_socket >= 0) {
- close(d_socket);
- }
- try {
- //cerr<<"Connecting to " << d_remote.toStringWithPort()<<endl;
- d_socket = SSocket(d_remote.sin4.sin_family, SOCK_STREAM, 0);
- SConnect(d_socket, d_remote);
- setNonBlocking(d_socket);
- }
- catch(const std::exception& e) {
- infolog("Error connecting to remote logger (%s): %s", d_remote.toStringWithPort(), e.what());
- return false;
- }
- return true;
-}
-
-bool RemoteLogger::sendData(const char* buffer, size_t bufferSize)
-{
- size_t pos = 0;
- while(pos < bufferSize) {
- //cerr<<"Sending "<< bufferSize-pos <<" to " << d_remote.toStringWithPort()<<endl;
- ssize_t written = write(d_socket, buffer + pos, bufferSize - pos);
- if (written == -1) {
- int res = errno;
- //cerr<<"errno is "<<errno<<endl;
- if (res == EWOULDBLOCK || res == EAGAIN) {
- return false;
- }
- else if (res != EINTR) {
- reconnect();
- return false;
- }
- }
- else if (written == 0) {
- reconnect();
- return false;
- }
- else {
- pos += (size_t) written;
- }
- }
-
- return true;
-}
-
-void RemoteLogger::worker()
-{
- while(true) {
- std::string data;
- {
- std::unique_lock<std::mutex> lock(d_writeMutex);
- d_queueCond.wait(lock, [this]{return !d_writeQueue.empty();});
- data = d_writeQueue.front();
- d_writeQueue.pop();
- }
-
- try {
- uint16_t len = data.length();
- len = htons(len);
- writen2WithTimeout(d_socket, &len, sizeof(len), (int) d_timeout);
- writen2WithTimeout(d_socket, data.c_str(), data.length(), (int) d_timeout);
- }
- catch(const std::runtime_error& e) {
- vinfolog("Error sending data to remote logger (%s): %s", d_remote.toStringWithPort(), e.what());
-
- while (!reconnect()) {
- sleep(d_reconnectWaitTime);
- }
- }
- }
-}
-
-void RemoteLogger::queueData(const std::string& data)
-{
- {
- std::unique_lock<std::mutex> lock(d_writeMutex);
- if (d_writeQueue.size() >= d_maxQueuedEntries) {
- d_writeQueue.pop();
- }
- d_writeQueue.push(data);
- }
- d_queueCond.notify_one();
-}
-
-RemoteLogger::RemoteLogger(const ComboAddress& remote, uint16_t timeout, uint64_t maxQueuedEntries, uint8_t reconnectWaitTime): d_remote(remote), d_maxQueuedEntries(maxQueuedEntries), d_timeout(timeout), d_reconnectWaitTime(reconnectWaitTime), d_thread(&RemoteLogger::worker, this)
-{
-#ifdef HAVE_PROTOBUF
- reconnect();
-#else
- throw new std::runtime_error("Remote logging requires protobuf support, which is not enabled.");
-#endif /* HAVE_PROTOBUF */
-}
-
-RemoteLogger::~RemoteLogger()
-{
- if (d_socket >= 0)
- close(d_socket);
-}
-
-void RemoteLogger::logQuery(const DNSQuestion& dq)
-{
-#ifdef HAVE_PROTOBUF
- PBDNSMessage message;
- message.set_type(PBDNSMessage_Type_DNSQueryType);
- message.set_messageid(boost::uuids::to_string(dq.uniqueId));
- message.set_socketfamily(dq.remote->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
- message.set_socketprotocol(dq.tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
- if (dq.local->sin4.sin_family == AF_INET) {
- message.set_to(&dq.local->sin4.sin_addr.s_addr, sizeof(dq.local->sin4.sin_addr.s_addr));
- }
- else if (dq.local->sin4.sin_family == AF_INET6) {
- message.set_to(&dq.local->sin6.sin6_addr.s6_addr, sizeof(dq.local->sin6.sin6_addr.s6_addr));
- }
- if (dq.remote->sin4.sin_family == AF_INET) {
- message.set_from(&dq.remote->sin4.sin_addr.s_addr, sizeof(dq.remote->sin4.sin_addr.s_addr));
- }
- else if (dq.remote->sin4.sin_family == AF_INET6) {
- message.set_from(&dq.remote->sin6.sin6_addr.s6_addr, sizeof(dq.remote->sin6.sin6_addr.s6_addr));
- }
- message.set_inbytes(dq.len);
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- message.set_timesec(ts.tv_sec);
- message.set_timeusec(ts.tv_nsec / 1000);
- message.set_id(ntohs(dq.dh->id));
-
- PBDNSMessage_DNSQuestion question;
- question.set_qname(dq.qname->toString());
- question.set_qtype(dq.qtype);
- question.set_qclass(dq.qclass);
- message.set_allocated_question(&question);
-
- //cerr <<message.DebugString()<<endl;
- std::string str;
- message.SerializeToString(&str);
- queueData(str);
- message.release_question();
-#endif /* HAVE_PROTOBUF */
-}
-
-#ifdef HAVE_PROTOBUF
-static void addRRs(const char* packet, const size_t len, PBDNSMessage_DNSResponse& response)
-{
- if (len < sizeof(struct dnsheader))
- return;
-
- const struct dnsheader* dh = (const struct dnsheader*) packet;
-
- if (ntohs(dh->ancount) == 0)
- return;
-
- if (ntohs(dh->qdcount) == 0)
- return;
-
- vector<uint8_t> content(len - sizeof(dnsheader));
- copy(packet + sizeof(dnsheader), packet + len, content.begin());
- PacketReader pr(content);
-
- size_t idx = 0;
- DNSName rrname;
- uint16_t qdcount = ntohs(dh->qdcount);
- uint16_t ancount = ntohs(dh->ancount);
- uint16_t rrtype;
- uint16_t rrclass;
- string blob;
- struct dnsrecordheader ah;
-
- rrname = pr.getName();
- rrtype = pr.get16BitInt();
- rrclass = pr.get16BitInt();
-
- /* consume remaining qd if any */
- if (qdcount > 1) {
- for(idx = 1; idx < qdcount; idx++) {
- rrname = pr.getName();
- rrtype = pr.get16BitInt();
- rrclass = pr.get16BitInt();
- (void) rrtype;
- (void) rrclass;
- }
- }
-
- /* parse AN */
- for (idx = 0; idx < ancount; idx++) {
- rrname = pr.getName();
- pr.getDnsrecordheader(ah);
-
- pr.xfrBlob(blob);
- if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
- PBDNSMessage_DNSResponse_DNSRR* rr = response.add_rrs();
- if (rr) {
- rr->set_name(rrname.toString());
- rr->set_type(ah.d_type);
- rr->set_class_(ah.d_class);
- rr->set_ttl(ah.d_ttl);
- rr->set_rdata(blob.c_str(), blob.length());
- }
- }
- }
-}
-#endif /* HAVE_PROTOBUF */
-
-void RemoteLogger::logResponse(const DNSQuestion& dr)
-{
-#ifdef HAVE_PROTOBUF
- PBDNSMessage message;
- message.set_type(PBDNSMessage_Type_DNSResponseType);
- message.set_messageid(boost::uuids::to_string(dr.uniqueId));
- message.set_socketfamily(dr.remote->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
- message.set_socketprotocol(dr.tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
- if (dr.local->sin4.sin_family == AF_INET) {
- message.set_from(&dr.local->sin4.sin_addr.s_addr, sizeof(dr.local->sin4.sin_addr.s_addr));
- }
- else if (dr.local->sin4.sin_family == AF_INET6) {
- message.set_from(&dr.local->sin6.sin6_addr.s6_addr, sizeof(dr.local->sin6.sin6_addr.s6_addr));
- }
- if (dr.remote->sin4.sin_family == AF_INET) {
- message.set_to(&dr.remote->sin4.sin_addr.s_addr, sizeof(dr.remote->sin4.sin_addr.s_addr));
- }
- else if (dr.remote->sin4.sin_family == AF_INET6) {
- message.set_to(&dr.remote->sin6.sin6_addr.s6_addr, sizeof(dr.remote->sin6.sin6_addr.s6_addr));
- }
- message.set_inbytes(dr.len);
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- message.set_timesec(ts.tv_sec);
- message.set_timeusec(ts.tv_nsec / 1000);
- message.set_id(ntohs(dr.dh->id));
-
- PBDNSMessage_DNSResponse response;
- response.set_rcode(dr.dh->rcode);
- addRRs((const char*) dr.dh, dr.len, response);
- message.set_allocated_response(&response);
-
-
- //cerr <<message.DebugString()<<endl;
- std::string str;
- message.SerializeToString(&str);
- queueData(str);
- message.release_response();
-#endif /* HAVE_PROTOBUF */
-}
+++ /dev/null
-#pragma once
-#include "config.h"
-
-#include <condition_variable>
-#include <queue>
-
-class RemoteLogger
-{
-public:
- RemoteLogger(const ComboAddress& remote, uint16_t timeout=2, uint64_t maxQueuedEntries=100, uint8_t reconnectWaitTime=1);
- ~RemoteLogger();
- void logQuery(const DNSQuestion& dq);
- void logResponse(const DNSQuestion& dr);
- std::string toString()
- {
- return d_remote.toStringWithPort();
- }
-private:
- bool reconnect();
- bool sendData(const char* buffer, size_t bufferSize);
- void worker();
- void queueData(const std::string& data);
-
- std::queue<std::string> d_writeQueue;
- std::mutex d_writeMutex;
- std::condition_variable d_queueCond;
- ComboAddress d_remote;
- uint64_t d_maxQueuedEntries;
- int d_socket{-1};
- uint16_t d_timeout;
- uint8_t d_reconnectWaitTime;
- std::thread d_thread;
-};
-
break;
}
+ dh = (struct dnsheader*) response;
DNSQuestion dr(&qname, qtype, qclass, &ci.cs->local, &ci.remote, dh, responseSize, responseLen, true);
#ifdef HAVE_PROTOBUF
dr.uniqueId = dq.uniqueId;
dnsdist-ecs.cc dnsdist-ecs.hh \
dnsdist-lua.cc \
dnsdist-lua2.cc \
- dnsdist-remotelogger.cc dnsdist-remotelogger.hh \
+ dnsdist-protobuf.cc dnsdist-protobuf.hh \
dnsdist-rings.cc \
dnsdist-tcp.cc \
dnsdist-web.cc \
namespaces.hh \
pdnsexception.hh \
qtype.cc qtype.hh \
+ remote_logger.cc remote_logger.hh \
sholder.hh \
sodcrypto.cc sodcrypto.hh \
sstuff.hh \
--- /dev/null
+../dnsdist-protobuf.cc
\ No newline at end of file
--- /dev/null
+../dnsdist-protobuf.hh
\ No newline at end of file
+++ /dev/null
-../dnsdist-remotelogger.cc
\ No newline at end of file
+++ /dev/null
-../dnsdist-remotelogger.hh
\ No newline at end of file
--- /dev/null
+../remote_logger.cc
\ No newline at end of file
--- /dev/null
+../remote_logger.hh
\ No newline at end of file
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
-#include <boost/uuid/uuid_io.hpp>
#include "dnsmessage.pb.h"
#include "iputils.hh"
if (!dh->qr) {
boost::uuids::uuid uniqueId = uuidGenerator();
ids[dh->id] = uniqueId;
- message.set_messageid(boost::uuids::to_string(uniqueId));
- question.set_qname(qname.toString());
- question.set_qtype(qtype);
- question.set_qclass(qclass);
- message.set_allocated_question(&question);
+ std::string* messageId = message.mutable_messageid();
+ messageId->resize(uniqueId.size());
+ std::copy(uniqueId.begin(), uniqueId.end(), messageId->begin());
}
else {
const auto& it = ids.find(dh->id);
if (it != ids.end()) {
- message.set_messageid(boost::uuids::to_string(it->second));
+ std::string* messageId = message.mutable_messageid();
+ messageId->resize(it->second.size());
+ std::copy(it->second.begin(), it->second.end(), messageId->begin());
}
+
response.set_rcode(dh->rcode);
addRRs((const char*) dh, pr.d_len, response);
message.set_allocated_response(&response);
}
+ question.set_qname(qname.toString());
+ question.set_qtype(qtype);
+ question.set_qclass(qclass);
+ message.set_allocated_question(&question);
std::string str;
//cerr<<message.DebugString()<<endl;
message.SerializeToString(&str);
#include "dolog.hh"
#include "ednsoptions.hh"
#include "lock.hh"
-#include "dnsdist-remotelogger.hh"
+#include "remote_logger.hh"
+#include "dnsdist-protobuf.hh"
class MaxQPSIPRule : public DNSRule
{
}
DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- d_logger->logQuery(*dq);
+#ifdef HAVE_PROTOBUF
+ std::string data;
+ protobufMessageFromQuestion(*dq, data);
+ d_logger->queueData(data);
+#endif /* HAVE_PROTOBUF */
return Action::None;
}
string toString() const override
}
DNSResponseAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- d_logger->logResponse(*dq);
+#ifdef HAVE_PROTOBUF
+ std::string data;
+ protobufMessageFromResponse(*dq, data);
+ d_logger->queueData(data);
+#endif /* HAVE_PROTOBUF */
return Action::None;
}
string toString() const override
#ifdef HAVE_PROTOBUF
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
-#include <boost/uuid/uuid_io.hpp>
#include "dnsmessage.pb.h"
#endif
#ifdef HAVE_PROTOBUF
static void protobufFillMessageFromDC(PBDNSMessage& message, const DNSComboWriter* dc)
{
- message.set_messageid(boost::uuids::to_string(dc->d_uuid));
+ std::string* messageId = message.mutable_messageid();
+ messageId->resize(dc->d_uuid.size());
+ std::copy(dc->d_uuid.begin(), dc->d_uuid.end(), messageId->begin());
+
message.set_socketfamily(dc->d_remote.sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
message.set_socketprotocol(dc->d_tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
if (dc->d_local.sin4.sin_family == AF_INET) {
message.set_timesec(ts.tv_sec);
message.set_timeusec(ts.tv_nsec / 1000);
message.set_id(ntohs(dc->d_mdp.d_header.id));
+
+ PBDNSMessage_DNSQuestion* question = message.mutable_question();
+ question->set_qname(dc->d_mdp.d_qname.toString());
+ question->set_qtype(dc->d_mdp.d_qtype);
+ question->set_qclass(dc->d_mdp.d_qclass);
}
static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, const DNSComboWriter* dc)
message.set_inbytes(dc->d_query.length());
protobufFillMessageFromDC(message, dc);
- PBDNSMessage_DNSQuestion question;
- question.set_qname(dc->d_mdp.d_qname.toString());
- question.set_qtype(dc->d_mdp.d_qtype);
- question.set_qclass(dc->d_mdp.d_qclass);
- message.set_allocated_question(&question);
-
// cerr <<message.DebugString()<<endl;
std::string str;
message.SerializeToString(&str);