* This file describes the message format used by the protobuf logging feature in PowerDNS and dnsdist.
*
* MIT License
- *
+ *
* Copyright (c) 2016-now PowerDNS.COM B.V. and its contributors.
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
optional uint64 workerId = 25; // Thread id
optional bool packetCacheHit = 26; // Was it a packet cache hit?
optional uint32 outgoingQueries = 27; // Number of outgoing queries used to answer the query
- optional uint32 headerFlags = 28; // Flags field in wire format
+ optional uint32 headerFlags = 28; // Flags field in wire format, 16 bits used
optional uint32 ednsVersion = 29; // EDNS version and flags in wire format, see https://www.rfc-editor.org/rfc/rfc6891.html#section-6.1.3
}
void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass,
bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options, boost::optional<uint32_t>& ednsVersion)
{
- const bool lookForECS = ednssubnet != nullptr;
const dnsheader_aligned dnshead(question.data());
const dnsheader* dhPointer = dnshead.get();
size_t questionLen = question.length();
const size_t headerSize = /* root */ 1 + sizeof(dnsrecordheader);
const uint16_t arcount = ntohs(dhPointer->arcount);
- for (uint16_t arpos = 0; arpos < arcount && questionLen >= (pos + headerSize) && (lookForECS && !foundECS); arpos++) {
+ for (uint16_t arpos = 0; arpos < arcount && questionLen >= (pos + headerSize) && !foundECS; arpos++) {
if (question.at(pos) != 0) {
/* not an OPT, bye. */
return;
}
/* OPT root label (1) followed by type (2) */
- if (lookForECS && ntohs(drh->d_type) == QType::OPT) {
+ if (ntohs(drh->d_type) == QType::OPT) {
if (options == nullptr) {
size_t ecsStartPosition = 0;
size_t ecsLen = 0;
const dnsheader* dnsheader = headerdata.get();
unsigned int ctag = 0;
uint32_t qhash = 0;
- bool needECS = false;
+ bool needEDNSParse = false;
std::unordered_set<std::string> policyTags;
std::map<std::string, RecursorLua4::MetaValue> meta;
LuaContext::LuaObject data;
const auto outgoingbExport = checkOutgoingProtobufExport(luaconfsLocal);
if (pbExport || outgoingbExport) {
if (pbExport) {
- needECS = true;
+ needEDNSParse = true;
}
uniqueId = getUniqueID();
}
#endif
// We do not have a SyncRes specific Lua context at this point yet, so ok to use t_pdl
- if (needECS || (t_pdl && (t_pdl->hasGettagFunc() || t_pdl->hasGettagFFIFunc())) || dnsheader->opcode == static_cast<unsigned>(Opcode::Notify)) {
+ if (needEDNSParse || (t_pdl && (t_pdl->hasGettagFunc() || t_pdl->hasGettagFFIFunc())) || dnsheader->opcode == static_cast<unsigned>(Opcode::Notify)) {
try {
EDNSOptionViewMap ednsOptions;
DNSName qname;
uint16_t qtype = 0;
uint16_t qclass = 0;
- bool needECS = false;
+ bool needEDNSParse = false;
string requestorId;
string deviceId;
string deviceName;
comboWriter->d_eventTrace.add(RecEventTrace::ReqRecv);
auto luaconfsLocal = g_luaconfs.getLocal();
if (checkProtobufExport(luaconfsLocal)) {
- needECS = true;
+ needEDNSParse = true;
}
logQuery = t_protobufServers.servers && luaconfsLocal->protobufExportConfig.logQueries;
comboWriter->d_logResponse = t_protobufServers.servers && luaconfsLocal->protobufExportConfig.logResponses;
- if (needECS || (t_pdl && (t_pdl->hasGettagFFIFunc() || t_pdl->hasGettagFunc())) || comboWriter->d_mdp.d_header.opcode == static_cast<unsigned>(Opcode::Notify)) {
+ if (needEDNSParse || (t_pdl && (t_pdl->hasGettagFFIFunc() || t_pdl->hasGettagFunc())) || comboWriter->d_mdp.d_header.opcode == static_cast<unsigned>(Opcode::Notify)) {
try {
EDNSOptionViewMap ednsOptions;
self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
self.checkNoRemainingMessage()
+ #
+ # again, for a PC cache hit
+ #
+ res = self.sendUDPQuery(query)
+
+ self.assertRRsetInAnswer(res, expected)
+
+ # check the protobuf messages corresponding to the UDP query and answer
+ msg = self.getFirstProtobufMessage()
+ self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+ # wire format, RD and CD set in headerflags, plus DO bit in flags part of EDNS Version
+ self.checkProtobufHeaderFlagsAndEDNSVersion(msg, 0x0110, 0x00008000)
+ # then the response
+ msg = self.getFirstProtobufMessage()
+ self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '127.0.0.1')
+ self.assertEqual(len(msg.response.rrs), 1)
+ rr = msg.response.rrs[0]
+ # we have max-cache-ttl set to 15
+ self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
+ self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+ self.checkNoRemainingMessage()
def testCNAME(self):
name = 'cname.example.'