dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc \
+ ednsoptions.cc \
ednssubnet.cc \
gss_context.cc gss_context.hh \
iputils.cc \
#include "dnsdist-ecs.hh"
#include "dnsparser.hh"
#include "dnswriter.hh"
+#include "ednsoptions.hh"
#include "ednssubnet.hh"
/* when we add EDNS to a query, we don't want to advertise
}
/* extract the start of the OPT RR in a QUERY packet if any */
-static int getEDNSOptionsStart(char* packet, const size_t offset, const size_t len, char ** optStart, size_t * remaining, unsigned char ** optRDLen)
+static int getEDNSOptionsStart(char* packet, const size_t offset, const size_t len, char ** optRDLen, size_t * remaining)
{
assert(packet != NULL);
- assert(optStart != NULL);
+ assert(optRDLen != NULL);
assert(remaining != NULL);
const struct dnsheader* dh = (const struct dnsheader*) packet;
if(qtype != QType::OPT || (len - pos) < (DNS_TTL_SIZE + DNS_RDLENGTH_SIZE))
return ENOENT;
- *optStart = packet + pos;
+ pos += DNS_TTL_SIZE;
+ *optRDLen = packet + pos;
*remaining = len - pos;
- if (optRDLen) {
- *optRDLen = ((unsigned char*) packet + pos + DNS_TTL_SIZE);
- }
-
return 0;
}
-/* extract a specific EDNS0 option from a pointer on the beginning of the OPT RR */
-static int getEDNSOption(char* optRR, const size_t len, const uint16_t wantedOption, char ** optionValue, size_t * optionValueSize)
-{
- assert(optRR != NULL);
- assert(optionValue != NULL);
- assert(optionValueSize != NULL);
- size_t pos = 0;
-
- pos += DNS_TTL_SIZE;
- const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
- size_t rdPos = 0;
- pos += DNS_RDLENGTH_SIZE;
-
- while(pos < (len - ((size_t) EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) &&
- rdPos < (rdLen - ((size_t) EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))) {
- const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
- pos += EDNS_OPTION_CODE_SIZE;
- rdPos += EDNS_OPTION_CODE_SIZE;
- const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
- pos += EDNS_OPTION_LENGTH_SIZE;
- rdPos += EDNS_OPTION_LENGTH_SIZE;
-
- if (optionLen > (rdLen - rdPos) || optionLen > (len - pos))
- return EINVAL;
-
- if (optionCode == wantedOption) {
- *optionValue = optRR + pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE);
- *optionValueSize = optionLen + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE;
- return 0;
- }
- else {
- /* skip this option */
- pos += optionLen;
- rdPos += optionLen;
- }
- }
-
- return ENOENT;
-}
-
-void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res)
-{
- const uint16_t ecsOptionCode = htons(optionCode);
- const uint16_t payloadLen = htons(payload.length());
- res.append((const char *) &ecsOptionCode, sizeof ecsOptionCode);
- res.append((const char *) &payloadLen, sizeof payloadLen);
- res.append(payload);
-}
-
static void generateECSOption(const ComboAddress& source, string& res)
{
Netmask sourceNetmask(source, source.sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6);
EDNSSubnetOpts ecsOpts;
ecsOpts.source = sourceNetmask;
string payload = makeEDNSSubnetOptsString(ecsOpts);
- generateEDNSOption(EDNS0_OPTION_CODE_ECS, payload, res);
+ generateEDNSOption(EDNSOptionCode::ECS, payload, res);
}
void generateOptRR(const std::string& optRData, string& res)
assert(len != NULL);
assert(consumed <= (size_t) *len);
assert(ednsAdded != NULL);
- char * optRRStart = NULL;
unsigned char * optRDLen = NULL;
size_t remaining = 0;
- int res = getEDNSOptionsStart(packet, consumed, *len, &optRRStart, &remaining, &optRDLen);
+ int res = getEDNSOptionsStart(packet, consumed, *len, (char**) &optRDLen, &remaining);
if (res == 0) {
char * ecsOptionStart = NULL;
size_t ecsOptionSize = 0;
- res = getEDNSOption(optRRStart, remaining, EDNS0_OPTION_CODE_ECS, &ecsOptionStart, &ecsOptionSize);
+ res = getEDNSOption((char*)optRDLen, remaining, EDNSOptionCode::ECS, &ecsOptionStart, &ecsOptionSize);
if (res == 0) {
- /* there is already an EDNS0_OPTION_CODE_ECS value */
+ /* there is already an ECS value */
if (g_ECSOverride) {
replaceEDNSClientSubnetOption(packet, packetSize, len, largerPacket, remote, ecsOptionStart, ecsOptionSize, optRDLen);
}
int locateEDNSOptRR(const char * packet, size_t len, const char ** optStart, size_t * optLen, bool * last);
void handleEDNSClientSubnet(char * packet, size_t packetSize, unsigned int consumed, uint16_t * len, string& largerPacket, bool * ednsAdded, const ComboAddress& remote);
void generateOptRR(const std::string& optRData, string& res);
-void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res);
-
-
-
EDNS_HEADER_FLAG_DO = 32768
};
-enum ednsOptionCodes {
- EDNS0_OPTION_CODE_NONE = 0,
- EDNS0_OPTION_CODE_ECS = 8,
-};
-
extern GlobalStateHolder<CarbonConfig> g_carbon;
extern GlobalStateHolder<ServerPolicy> g_policy;
extern GlobalStateHolder<servers_t> g_dstates;
dnsrulactions.hh \
dnswriter.cc dnswriter.hh \
dolog.hh \
+ ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
iputils.cc iputils.hh \
lock.hh \
dnsparser.hh dnsparser.cc \
dnswriter.cc dnswriter.hh \
dolog.hh \
+ ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
iputils.cc iputils.hh \
misc.cc misc.hh \
--- /dev/null
+../ednsoptions.cc
\ No newline at end of file
--- /dev/null
+../ednsoptions.hh
\ No newline at end of file
#include "dnsdist-ecs.hh"
#include "dnsname.hh"
#include "dolog.hh"
+#include "ednsoptions.hh"
class MaxQPSIPRule : public DNSRule
{
--- /dev/null
+
+#include "dns.hh"
+#include "ednsoptions.hh"
+#include "iputils.hh"
+
+/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
+int getEDNSOption(char* optRR, const size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize)
+{
+ assert(optRR != NULL);
+ assert(optionValue != NULL);
+ assert(optionValueSize != NULL);
+ size_t pos = 0;
+ if (len < DNS_RDLENGTH_SIZE)
+ return EINVAL;
+
+ const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
+ size_t rdPos = 0;
+ pos += DNS_RDLENGTH_SIZE;
+ if ((pos + rdLen) > len) {
+ return EINVAL;
+ }
+
+ while(len >= (pos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE) &&
+ rdLen >= (rdPos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) {
+ const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
+ pos += EDNS_OPTION_CODE_SIZE;
+ rdPos += EDNS_OPTION_CODE_SIZE;
+ const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
+ pos += EDNS_OPTION_LENGTH_SIZE;
+ rdPos += EDNS_OPTION_LENGTH_SIZE;
+ if (optionLen > (rdLen - rdPos) || optionLen > (len - pos))
+ return EINVAL;
+
+ if (optionCode == wantedOption) {
+ *optionValue = optRR + pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE);
+ *optionValueSize = optionLen + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE;
+ return 0;
+ }
+ else {
+ /* skip this option */
+ pos += optionLen;
+ rdPos += optionLen;
+ }
+ }
+
+ return ENOENT;
+}
+
+void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res)
+{
+ const uint16_t ednsOptionCode = htons(optionCode);
+ const uint16_t payloadLen = htons(payload.length());
+ res.append((const char *) &ednsOptionCode, sizeof ednsOptionCode);
+ res.append((const char *) &payloadLen, sizeof payloadLen);
+ res.append(payload);
+}
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2011 - 2016 Netherlabs Computer Consulting BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifndef PDNS_EDNSOPTIONS_HH
+#define PDNS_EDNSOPTIONS_HH
+
+#include "namespaces.hh"
+
+struct EDNSOptionCode
+{
+ enum EDNSOptionCodeEnum {NSID=3, DAU=4, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13};
+};
+
+/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
+int getEDNSOption(char* optRR, size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize);
+void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res);
+
+#endif
#include "rpzloader.hh"
#include "validate-recursor.hh"
#include "rec-lua-conf.hh"
+#include "ednsoptions.hh"
#ifndef RECURSOR
#include "statbag.hh"
unsigned int consumed=0;
uint16_t qtype=0;
try {
- DNSName qname(question.c_str(), question.length(), sizeof(dnsheader), false, &qtype, 0, &consumed);
+ size_t questionLen = question.length();
+ DNSName qname(question.c_str(), questionLen, sizeof(dnsheader), false, &qtype, 0, &consumed);
Netmask ednssubnet;
- auto pos= sizeof(dnsheader)+consumed+4;
- if(ntohs(dh->arcount) == 1 && question.length() > pos + 16) { // this code can extract one (1) EDNS Subnet option
- uint16_t optlen=0x100*question.at(pos+9)+question.at(pos+10);
- uint16_t optcode=0x100*question.at(pos+11)+question.at(pos+12);
- if(question.at(pos)==0 && question.at(pos+1)==0 && question.at(pos+2)==QType::OPT && optlen && optcode==8) {
- EDNSSubnetOpts eso;
- if(getEDNSSubnetOptsFromString(question.c_str()+pos+15, question.length()-15-pos, &eso)) {
- ednssubnet=eso.source;
+ size_t pos= sizeof(dnsheader)+consumed+4;
+ /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2)
+ = 11 */
+ if(ntohs(dh->arcount) == 1 && questionLen > pos + 11) { // this code can extract one (1) EDNS Subnet option
+ /* OPT root label (1) followed by type (2) */
+ if(question.at(pos)==0 && question.at(pos+1)==0 && question.at(pos+2)==QType::OPT) {
+ char* ecsStart = nullptr;
+ size_t ecsLen = 0;
+ int res = getEDNSOption((char*)question.c_str()+pos+9, questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStart, &ecsLen);
+ if (res == 0 && ecsLen > 4) {
+ EDNSSubnetOpts eso;
+ if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
+ ednssubnet=eso.source;
+ }
}
}
}
#include "namespaces.hh"
#include "lock.hh"
#include "dnswriter.hh"
+#include "ednsoptions.hh"
RecursorPacketCache::RecursorPacketCache()
{
= 16
*/
if(ntohs(dh->arcount)==1 && (p+16) < end) {
+ char* optionBegin = nullptr;
+ size_t optionLen = 0;
/* skip the final empty label (1), the qtype (2), qclass (2) */
/* root label (1), type (2), class (2) and ttl (4) */
- const unsigned char *q = (const unsigned char*) p + 14;
- uint16_t optRRLen = (0x100*q[0] + q[1]);
- q += 2;
- if ((q + optRRLen) <= (const unsigned char*) end) {
- const unsigned char* optRRend = q + optRRLen;
- while((q + 4) <= optRRend) {
- const unsigned char* optionBegin = q;
- uint16_t optionCode = 0x100*q[0] + q[1];
- //cout << "OPT RR Option Code is " << optionCode << endl;
- q += 2;
- uint16_t optionLen = 0x100*q[0] + q[1];
- //cout << "OPT RR Option Length is " << optionLen << endl;
- q += 2;
- if ((q + optionLen) > (const unsigned char*) end) {
- break;
- }
- if (optionCode == 8) {
- //cout << "Skipping OPT RR Option Client Subnet:" << endl;
- //cout << makeHexDump(string((const char*)optionBegin, (const char*) q + optionLen)) << endl;
- skipBegin = (const char*) optionBegin;
- skipEnd = (const char*) q + optionLen;
- break;
- }
- q += optionLen;
- }
+ int res = getEDNSOption((char*) p + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen);
+ if (res == 0) {
+ skipBegin = optionBegin;
+ skipEnd = optionBegin + optionLen;
}
}
if (skipBegin > p) {
dnssecinfra.hh dnssecinfra.cc \
dnsseckeeper.hh \
dnswriter.cc dnswriter.hh \
+ ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
filterpo.cc filterpo.hh \
gss_context.cc gss_context.hh \
--- /dev/null
+../ednsoptions.cc
\ No newline at end of file
--- /dev/null
+../ednsoptions.hh
\ No newline at end of file
#include "dnsname.hh"
#include "dnsparser.hh"
#include "dnswriter.hh"
+#include "ednsoptions.hh"
#include "ednssubnet.hh"
#include <unistd.h>
ecsOpts.source = Netmask(origRemote, g_ECSSourcePrefixV4);
string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
DNSPacketWriter::optvect_t opts;
- opts.push_back(make_pair(EDNS0_OPTION_CODE_ECS, origECSOption));
+ opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
uint16_t len = query.size();
ecsOpts.source = Netmask(origRemote, 32);
string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
DNSPacketWriter::optvect_t opts;
- opts.push_back(make_pair(EDNS0_OPTION_CODE_ECS, origECSOption));
+ opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
uint16_t len = query.size();
ecsOpts.source = Netmask(origRemote, 8);
string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
DNSPacketWriter::optvect_t opts;
- opts.push_back(make_pair(EDNS0_OPTION_CODE_ECS, origECSOption));
+ opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
uint16_t len = query.size();