dnsdist-console.cc dnsdist-console.hh \
dnsdist-discovery.cc dnsdist-discovery.hh \
dnsdist-dnscrypt.cc \
+ dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
dnsdist-downstream-connection.hh \
dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
dnscrypt.cc dnscrypt.hh \
dnsdist-backend.cc \
dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
dnsdist-downstream-connection.hh \
dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsdist-dnsparser.hh"
+#include "dnsparser.hh"
+
+namespace dnsdist
+{
+DNSPacketOverlay::DNSPacketOverlay(const std::string_view& packet)
+{
+ if (packet.size() < sizeof(dnsheader)) {
+ throw std::runtime_error("Packet is too small for a DNS packet");
+ }
+
+ memcpy(&d_header, packet.data(), sizeof(dnsheader));
+ uint64_t numRecords = ntohs(d_header.ancount) + ntohs(d_header.nscount) + ntohs(d_header.arcount);
+ d_records.reserve(numRecords);
+
+ try
+ {
+ PacketReader reader(pdns_string_view(reinterpret_cast<const char*>(packet.data()), packet.size()));
+
+ for (uint16_t n = 0; n < ntohs(d_header.qdcount) ; ++n) {
+ reader.xfrName(d_qname);
+ reader.xfrType(d_qtype);
+ reader.xfrType(d_qclass);
+ }
+
+ for (uint64_t n = 0; n < numRecords; ++n) {
+ Record rec;
+ reader.xfrName(rec.d_name);
+ rec.d_place = n < ntohs(d_header.ancount) ? DNSResourceRecord::ANSWER : (n < (ntohs(d_header.ancount) + ntohs(d_header.nscount)) ? DNSResourceRecord::AUTHORITY : DNSResourceRecord::ADDITIONAL);
+ reader.xfrType(rec.d_type);
+ reader.xfrType(rec.d_class);
+ reader.xfr32BitInt(rec.d_ttl);
+ reader.xfr16BitInt(rec.d_contentLength);
+ rec.d_contentOffset = reader.getPosition();
+ reader.skip(rec.d_contentLength);
+ d_records.push_back(std::move(rec));
+ }
+ }
+ catch (const std::exception& e) {
+ throw std::runtime_error("Unable to parse DNS packet: " + std::string(e.what()));
+ }
+ catch (const PDNSException& e) {
+ throw std::runtime_error("Unable to parse DNS packet: " + e.reason);
+ }
+ catch (...) {
+ throw std::runtime_error("Unable to parse DNS packet");
+ }
+}
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "dnsparser.hh"
+
+namespace dnsdist
+{
+class DNSPacketOverlay
+{
+public:
+ DNSPacketOverlay(const std::string_view& packet);
+
+ struct Record
+ {
+ DNSName d_name;
+ uint32_t d_ttl;
+ uint16_t d_type;
+ uint16_t d_class;
+ uint16_t d_contentLength;
+ uint16_t d_contentOffset;
+ DNSResourceRecord::Place d_place;
+ };
+
+ DNSName d_qname;
+ std::vector<Record> d_records;
+ uint16_t d_qtype;
+ uint16_t d_qclass;
+ dnsheader d_header;
+};
+}
bool dnsdist_ffi_network_endpoint_is_valid(const dnsdist_ffi_network_endpoint_t* endpoint) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_network_endpoint_send(const dnsdist_ffi_network_endpoint_t* endpoint, const char* payload, size_t payloadSize) __attribute__ ((visibility ("default")));
void dnsdist_ffi_network_endpoint_free(dnsdist_ffi_network_endpoint_t* endpoint) __attribute__ ((visibility ("default")));
+
+typedef struct dnsdist_ffi_dnspacket_t dnsdist_ffi_dnspacket_t;
+
+bool dnsdist_ffi_dnspacket_parse(const char* packet, size_t packetSize, dnsdist_ffi_dnspacket_t** out) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnspacket_get_qname_raw(const dnsdist_ffi_dnspacket_t* packet, const char** qname, size_t* qnameSize) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_qtype(const dnsdist_ffi_dnspacket_t* packet) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_qclass(const dnsdist_ffi_dnspacket_t* packet) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_records_count_in_section(const dnsdist_ffi_dnspacket_t* packet, uint8_t section) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnspacket_get_record_name_raw(const dnsdist_ffi_dnspacket_t* packet, size_t idx, const char** name, size_t* nameSize) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_record_type(const dnsdist_ffi_dnspacket_t* packet, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_record_class(const dnsdist_ffi_dnspacket_t* packet, size_t idx) __attribute__ ((visibility ("default")));
+uint32_t dnsdist_ffi_dnspacket_get_record_ttl(const dnsdist_ffi_dnspacket_t* packet, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_record_content_length(const dnsdist_ffi_dnspacket_t* packet, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_dnspacket_get_record_content_offset(const dnsdist_ffi_dnspacket_t* packet, size_t idx) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnspacket_free(dnsdist_ffi_dnspacket_t*) __attribute__ ((visibility ("default")));
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-lua-ffi.hh"
#include "dnsdist-mac-address.hh"
#include "dnsdist-lua-network.hh"
{
delete endpoint;
}
+
+struct dnsdist_ffi_dnspacket_t
+{
+ dnsdist::DNSPacketOverlay overlay;
+};
+
+bool dnsdist_ffi_dnspacket_parse(const char* packet, size_t packetSize, dnsdist_ffi_dnspacket_t** out)
+{
+ if (out == nullptr || packetSize < sizeof(dnsheader)) {
+ return false;
+ }
+
+ try {
+ dnsdist::DNSPacketOverlay overlay(std::string_view(packet, packetSize));
+ *out = new dnsdist_ffi_dnspacket_t{std::move(overlay)};
+ return true;
+ }
+ catch (const std::exception& e) {
+ vinfolog("Error in dnsdist_ffi_dnspacket_parse: %s", e.what());
+ }
+ catch (...) {
+ vinfolog("Error in dnsdist_ffi_dnspacket_parse");
+ }
+ return false;
+}
+
+void dnsdist_ffi_dnspacket_get_qname_raw(const dnsdist_ffi_dnspacket_t* packet, const char** qname, size_t* qnameSize)
+{
+ if (packet == nullptr || qname == nullptr || qnameSize == nullptr) {
+ return;
+ }
+ const auto& storage = packet->overlay.d_qname.getStorage();
+ *qname = storage.data();
+ *qnameSize = storage.size();
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_qtype(const dnsdist_ffi_dnspacket_t* packet)
+{
+ if (packet != nullptr) {
+ return packet->overlay.d_qtype;
+ }
+ return 0;
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_qclass(const dnsdist_ffi_dnspacket_t* packet)
+{
+ if (packet != nullptr) {
+ return packet->overlay.d_qclass;
+ }
+ return 0;
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_records_count_in_section(const dnsdist_ffi_dnspacket_t* packet, uint8_t section)
+{
+ if (packet == nullptr || section > 3) {
+ return 0;
+ }
+
+ uint16_t count = 0;
+ for (const auto& record : packet->overlay.d_records) {
+ if (record.d_place == section) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void dnsdist_ffi_dnspacket_get_record_name_raw(const dnsdist_ffi_dnspacket_t* packet, size_t idx, const char** name, size_t* nameSize)
+{
+ if (packet == nullptr || name == nullptr || nameSize == nullptr || idx > packet->overlay.d_records.size()) {
+ return;
+ }
+ const auto& storage = packet->overlay.d_records.at(idx).d_name.getStorage();
+ *name = storage.data();
+ *nameSize = storage.size();
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_record_type(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
+{
+ if (packet == nullptr || idx > packet->overlay.d_records.size()) {
+ return 0;
+ }
+ return packet->overlay.d_records.at(idx).d_type;
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_record_class(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
+{
+ if (packet == nullptr || idx > packet->overlay.d_records.size()) {
+ return 0;
+ }
+ return packet->overlay.d_records.at(idx).d_class;
+}
+
+uint32_t dnsdist_ffi_dnspacket_get_record_ttl(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
+{
+ if (packet == nullptr || idx > packet->overlay.d_records.size()) {
+ return 0;
+ }
+ return packet->overlay.d_records.at(idx).d_ttl;
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_record_content_length(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
+{
+ if (packet == nullptr || idx > packet->overlay.d_records.size()) {
+ return 0;
+ }
+ return packet->overlay.d_records.at(idx).d_contentLength;
+}
+
+uint16_t dnsdist_ffi_dnspacket_get_record_content_offset(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
+{
+ if (packet == nullptr || idx > packet->overlay.d_records.size()) {
+ return 0;
+ }
+ return packet->overlay.d_records.at(idx).d_contentOffset;
+}
+
+void dnsdist_ffi_dnspacket_free(dnsdist_ffi_dnspacket_t* packet)
+{
+ if (packet != nullptr) {
+ delete packet;
+ }
+}