generateEDNSOption(EDNSOptionCode::ECS, payload, res);
}
-void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, bool dnssecOK)
+void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, uint16_t ednsrcode, bool dnssecOK)
{
const uint8_t name = 0;
dnsrecordheader dh;
EDNS0Record edns0;
- edns0.extRCode = 0;
+ edns0.extRCode = ednsrcode;
edns0.version = 0;
edns0.extFlags = dnssecOK ? htons(EDNS_HEADER_FLAG_DO) : 0;
/* we need to add a EDNS0 RR with one EDNS0 ECS option, fixing the AR count */
string EDNSRR;
struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet);
- generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, false);
+ generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, 0, false);
/* does it fit in the existing buffer? */
if (packetSize - *len <= EDNSRR.size()) {
return 0;
}
-bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize)
+bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint16_t ednsrcode)
{
if (dh->arcount != 0) {
return false;
}
std::string optRecord;
- generateOptRR(std::string(), optRecord, payloadSize, dnssecOK);
+ generateOptRR(std::string(), optRecord, payloadSize, ednsrcode, dnssecOK);
if (optRecord.size() >= size || (size - optRecord.size()) < len) {
return false;
if (g_addEDNSToSelfGeneratedResponses) {
/* now we need to add a new OPT record */
- return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers);
+ return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
}
/* otherwise we are just fine */
return false;
}
+
+int getEDNSVersion(const DNSQuestion& dq)
+try
+{
+ if (ntohs(dq.dh->qdcount) != 1 || dq.dh->ancount != 0 || ntohs(dq.dh->arcount) != 1 || dq.dh->nscount != 0) {
+ return 0;
+ }
+
+ if (dq.len <= sizeof(dnsheader)) {
+ return 0;
+ }
+
+ size_t pos = sizeof(dnsheader) + dq.consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
+
+ if (dq.len <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
+ return 0;
+ }
+
+ const char* packet = reinterpret_cast<const char*>(dq.dh);
+
+ if (packet[pos] != 0) {
+ /* not root, so not a valid OPT record */
+ return 0;
+ }
+
+ pos++;
+
+ uint16_t qtype = (reinterpret_cast<const unsigned char*>(packet)[pos])*256 + reinterpret_cast<const unsigned char*>(packet)[pos+1];
+ pos += DNS_TYPE_SIZE;
+ pos += DNS_CLASS_SIZE;
+
+ if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + 1) >= dq.len) {
+ return 0;
+ }
+
+ const uint8_t* z = reinterpret_cast<const uint8_t*>(packet) + pos + EDNS_EXTENDED_RCODE_SIZE;
+ return 0x100 * (*z) + *(z+1);
+}
+catch(...)
+{
+ return 0;
+}
int rewriteResponseWithoutEDNS(const std::string& initialPacket, vector<uint8_t>& newContent);
int locateEDNSOptRR(const std::string& packet, uint16_t * optStart, size_t * optLen, bool * last);
-void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, bool dnssecOK);
+void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, uint16_t ednsrcode, bool dnssecOK);
void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength);
int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove);
int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uint16_t optionCodeToSkip, vector<uint8_t>& newContent);
int getEDNSOptionsStart(const char* packet, const size_t offset, const size_t len, uint16_t* optRDPosition, size_t * remaining);
bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr);
-bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize);
+bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint16_t ednsrcode);
bool addEDNSToQueryTurnedResponse(DNSQuestion& dq);
bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded, bool preserveTrailingData);
int getEDNSZ(const DNSQuestion& dq);
bool queryHasEDNS(const DNSQuestion& dq);
+int getEDNSVersion(const DNSQuestion& dq);
dq->dh->ancount = htons(dq->dh->ancount);
if (hadEDNS) {
- addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers);
+ addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
}
return Action::HeaderModify;
generateEDNSOption(d_code, mac, optRData);
string res;
- generateOptRR(optRData, res, g_EdnsUDPPayloadSize, false);
+ generateOptRR(optRData, res, g_EdnsUDPPayloadSize, 0, false);
if ((dq->size - dq->len) < res.length())
return Action::None;
dh->ancount = dh->arcount = dh->nscount = 0;
if (hadEDNS) {
- addEDNS(dh, *len, responseSize, z & EDNS_HEADER_FLAG_DO, payloadSize);
+ addEDNS(dh, *len, responseSize, z & EDNS_HEADER_FLAG_DO, payloadSize, 0);
}
}
catch(...)
return;
}
+ if (queryHasEDNS(dq) && getEDNSVersion(dq) > 0) {
+ dq.dh->qr = true;
+ dq.dh->rcode = (16 & 0xF);
+ dq.ednsRCode = ((16 & 0xFFF0)>>4); // set rcode to BADVERS
+ }
+
if(dq.dh->qr) { // something turned it into a response
fixUpQueryTurnedResponse(dq, origFlags);
unsigned int consumed{0};
uint16_t len;
uint16_t ecsPrefixLength;
+ uint16_t ednsRCode; // WARNING: this is really 12 bits
boost::optional<uint32_t> tempFailureTTL;
const bool tcp;
const struct timespec* queryTime;