Maximum number of empty non-terminals to add to a zone. This is a
protection measure to avoid database explosion due to long names.
+.. _setting-max-generate-steps:
+
+``max-generate-steps``
+----------------------
+
+.. versionadded:: 4.3.0
+
+- Integer
+- Default: 0
+
+Maximum number of steps for a '$GENERATE' directive when parsing a
+zone file. This is a protection measure to prevent consuming a lot of
+CPU and memory when untrusted zones are loaded. Default to 0 which
+means unlimited.
+
.. _setting-max-nsec3-iterations:
``max-nsec3-iterations``
nsec3zone=getNSEC3PARAM(bbd->d_name, &ns3pr);
bbd->d_records = shared_ptr<recordstorage_t>(new recordstorage_t());
-
ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
string hashed;
- while(zpt.get(rr)) {
+ while(zpt.get(rr)) {
if(rr.qtype.getCode() == QType::NSEC || rr.qtype.getCode() == QType::NSEC3 || rr.qtype.getCode() == QType::NSEC3PARAM)
continue; // we synthesise NSECs on demand
::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
+ ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
+
::arg().set("rng", "Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
}
boost::split(lines, tmp, boost::is_any_of("\n"));
ZoneParserTNG zpt(lines, g_rootdnsname);
+ /* limit the number of steps for '$GENERATE' entries */
+ zpt.setMaxGenerateSteps(10000);
DNSResourceRecord drr;
while (zpt.get(drr)) {
}
::arg().set("distribution-load-factor", "The load factor used when PowerDNS is distributing queries to worker threads")="0.0";
::arg().setSwitch("qname-minimization", "Use Query Name Minimization")="no";
::arg().setSwitch("nothing-below-nxdomain", "When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)")="yes";
+ ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
#ifdef NOD_ENABLED
::arg().set("new-domain-tracking", "Track newly observed domains (i.e. never seen before).")="no";
::arg().set("new-domain-log", "Log newly observed domains.")="yes";
::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
+ ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
::arg().laxFile(configname.c_str());
if(!::arg()["load-modules"].empty()) {
}
cmdline.clear();
ZoneParserTNG zpt(tmpnam, g_rootdnsname);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord zrr;
map<pair<DNSName,uint16_t>, vector<DNSRecord> > grouped;
try {
}
DNSBackend* db = di.backend;
ZoneParserTNG zpt(fname, zone);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
if(!db->startTransaction(zone, di.id)) {
void verifyCrypto(const string& zone)
{
ZoneParserTNG zpt(zone);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
DNSKEYRecordContent drc;
RRSIGRecordContent rrc;
connection. This number must be larger than 0 and smaller than 65536
and also smaller than `max-mthreads`.
+.. _setting-max-generate-steps:
+
+``max-generate-steps``
+----------------------
+
+.. versionadded:: 4.3.0
+
+- Integer
+- Default: 0
+
+Maximum number of steps for a '$GENERATE' directive when parsing a
+zone file. This is a protection measure to prevent consuming a lot of
+CPU and memory when untrusted zones are loaded. Default to 0 which
+means unlimited.
.. _setting-max-mthreads:
}
else {
ZoneParserTNG zpt(::arg()["hint-file"]);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
while(zpt.get(rr)) {
ad.d_rdForward = false;
g_log<<Logger::Error<<"Parsing authoritative data for zone '"<<headers.first<<"' from file '"<<headers.second<<"'"<<endl;
ZoneParserTNG zpt(headers.second, DNSName(headers.first));
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
DNSRecord dr;
while(zpt.get(rr)) {
stringtok(zonedata, zonestring, "\r\n");
ZoneParserTNG zpt(zonedata, zonename);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
bool seenSOA=false;
::arg().set("soa-refresh-default","Do not change")="0";
::arg().set("soa-retry-default","Do not change")="0";
::arg().set("soa-expire-default","Do not change")="0";
+ ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
::arg().setCmd("help","Provide a helpful message");
::arg().setCmd("version","Print the version");
Json::object obj;
Json::array recs;
ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
obj["name"] = i->name.toString();
}
else {
ZoneParserTNG zpt(zonefile, DNSName(::arg()["zone-name"]));
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
string zname;
Json::object obj;
args.set( "layout", "How to arrange entries in the directory (simple or as tree)" ) = "simple";
args.set( "domainid", "Domain ID of the first domain found (incremented afterwards)" ) = "1";
args.set( "metadata-dn", "DN under which to store the domain metadata" ) = "";
+ args.set( "max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
args.parse( argc, argv );
cerr << "Parsing file: " << i.filename << ", domain: " << i.name << endl;
g_zonename = i.name;
ZoneParserTNG zpt(i.filename, i.name, BP.getDirectory());
+ zpt.setMaxGenerateSteps(args.asNum("max-generate-steps"));
DNSResourceRecord rr;
while(zpt.get(rr)) {
callback(g_domainid, rr.qname, rr.qtype.getName(), encode_non_ascii(rr.content), rr.ttl);
g_zonename = DNSName(args["zone-name"]);
ZoneParserTNG zpt(args["zone-file"], g_zonename);
+ zpt.setMaxGenerateSteps(args.asNum("max-generate-steps"));
DNSResourceRecord rr;
while(zpt.get(rr)) {
callback(g_domainid, rr.qname, rr.qtype.getName(), encode_non_ascii(rr.content), rr.ttl);
::arg().set("soa-refresh-default","Do not change")="0";
::arg().set("soa-retry-default","Do not change")="0";
::arg().set("soa-expire-default","Do not change")="0";
+ ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
::arg().setCmd("help","Provide a helpful message");
::arg().setCmd("version","Print the version");
emitDomain(i->name, &(i->masters));
ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
bool seenSOA=false;
string comment;
zonename = DNSName(::arg()["zone-name"]);
ZoneParserTNG zpt(zonefile, zonename);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
startNewTransaction();
string comment;
d_templatestop < d_templatecounter) {
throw exception("Invalid $GENERATE parameters");
}
+ if (d_maxGenerateSteps != 0) {
+ size_t numberOfSteps = (d_templatestop - d_templatecounter) / d_templatestep;
+ if (numberOfSteps > d_maxGenerateSteps) {
+ throw exception("The number of $GENERATE steps (" + std::to_string(numberOfSteps) + ") is too high, the maximum is set to " + std::to_string(d_maxGenerateSteps));
+ }
+ }
d_templateline=d_line;
parts.pop_front();
parts.pop_front();
DNSName getZoneName();
string getLineOfFile(); // for error reporting purposes
pair<string,int> getLineNumAndFile(); // idem
+ void setMaxGenerateSteps(size_t max)
+ {
+ d_maxGenerateSteps = max;
+ }
private:
bool getLine();
bool getTemplateLine();
vector<string>::iterator d_zonedataline;
std::stack<filestate> d_filestates;
parts_t d_templateparts;
+ size_t d_maxGenerateSteps{0};
int d_defaultttl;
uint32_t d_templatecounter, d_templatestop, d_templatestep;
bool d_havedollarttl;