]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/zoneparser-tng.cc
clang-tidy: IsTimeSpec function: curly + implicit conversions.
[thirdparty/pdns.git] / pdns / zoneparser-tng.cc
CommitLineData
f814d7c8 1/*
6edbf68a
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
f814d7c8
BH
25#include "dnsparser.hh"
26#include "sstuff.hh"
27#include "misc.hh"
28#include "dnswriter.hh"
29#include "dnsrecords.hh"
f814d7c8
BH
30#include <fstream>
31#include "dns.hh"
32#include "zoneparser-tng.hh"
125e4840
BH
33#include <deque>
34#include <boost/algorithm/string.hpp>
e0e48a7a 35#include <system_error>
1817fef6 36#include <cinttypes>
e3fc3ebd 37#include <sys/stat.h>
f814d7c8 38
e3fc3ebd 39const static string g_INstr("IN");
3108d502 40
1290c1d2 41ZoneParserTNG::ZoneParserTNG(const string& fname, DNSName zname, string reldir, bool upgradeContent):
1e05b07c 42 d_reldir(std::move(reldir)), d_zonename(std::move(zname)), d_defaultttl(3600),
b4db4fe4
CH
43 d_templatecounter(0), d_templatestop(0), d_templatestep(0),
44 d_havedollarttl(false), d_fromfile(true), d_upgradeContent(upgradeContent)
45{
bf503cc0
BH
46 stackFile(fname);
47}
48
1290c1d2
RP
49ZoneParserTNG::ZoneParserTNG(const vector<string>& zonedata, DNSName zname, bool upgradeContent):
50 d_zonename(std::move(zname)), d_zonedata(zonedata), d_defaultttl(3600),
8a70e507 51 d_templatecounter(0), d_templatestop(0), d_templatestep(0),
b4db4fe4 52 d_havedollarttl(false), d_fromfile(false), d_upgradeContent(upgradeContent)
0f0e73fe 53{
0f0e73fe 54 d_zonedataline = d_zonedata.begin();
0f0e73fe
MS
55}
56
bf503cc0
BH
57void ZoneParserTNG::stackFile(const std::string& fname)
58{
e3fc3ebd
OM
59 if (d_filestates.size() >= d_maxIncludes) {
60 std::error_code ec (0, std::generic_category());
61 throw std::system_error(ec, "Include limit reached");
62 }
63 int fd = open(fname.c_str(), O_RDONLY, 0);
64 if (fd == -1) {
65 int err = errno;
66 std::error_code ec (err, std::generic_category());
67 throw std::system_error(ec, "Unable to open file '" + fname + "': " + stringerror(err));
68 }
69 struct stat st;
70 if (fstat(fd, &st) == -1) {
71 int err = errno;
72 close(fd);
73 std::error_code ec (err, std::generic_category());
74 throw std::system_error(ec, "Unable to stat file '" + fname + "': " + stringerror(err));
75 }
76 if (!S_ISREG(st.st_mode)) {
77 close(fd);
78 std::error_code ec (0, std::generic_category());
79 throw std::system_error(ec, "File '" + fname + "': not a regular file");
80 }
81 FILE *fp = fdopen(fd, "r");
3700e0dd 82 if (fp == nullptr) {
e3fc3ebd
OM
83 int err = errno;
84 close(fd);
85 std::error_code ec (err, std::generic_category());
86 throw std::system_error(ec, "Unable to open file '" + fname + "': " + stringerror(err));
e0e48a7a 87 }
cfe397d5
BH
88
89 filestate fs(fp, fname);
90 d_filestates.push(fs);
0f0e73fe 91 d_fromfile = true;
f814d7c8
BH
92}
93
94ZoneParserTNG::~ZoneParserTNG()
95{
cfe397d5
BH
96 while(!d_filestates.empty()) {
97 fclose(d_filestates.top().d_fp);
98 d_filestates.pop();
bf503cc0 99 }
f814d7c8
BH
100}
101
125e4840
BH
102static string makeString(const string& line, const pair<string::size_type, string::size_type>& range)
103{
104 return string(line.c_str() + range.first, range.second - range.first);
105}
106
cfe397d5
BH
107static bool isTimeSpec(const string& nextpart)
108{
eb914147 109 if (nextpart.empty()) {
cfe397d5 110 return false;
eb914147
AV
111 }
112
78924ce1 113 for (auto iter = nextpart.begin(); iter != nextpart.end(); ++iter) {
eb914147
AV
114 auto current = static_cast<unsigned char>(*iter);
115 if (isdigit(current) != 0) {
cfe397d5 116 continue;
eb914147
AV
117 }
118
119 if (iter + 1 != nextpart.end()) {
cfe397d5 120 return false;
eb914147
AV
121 }
122
123 char c = static_cast<char>(tolower(current));
2326ec3f 124 return (c=='s' || c=='m' || c=='h' || c=='d' || c=='w' || c=='y');
cfe397d5
BH
125 }
126 return true;
127}
128
129
130unsigned int ZoneParserTNG::makeTTLFromZone(const string& str)
125e4840
BH
131{
132 if(str.empty())
133 return 0;
134
97ce13be
RG
135 unsigned int val;
136 try {
a0383aad 137 pdns::checked_stoi_into(val, str);
97ce13be
RG
138 }
139 catch (const std::out_of_range& oor) {
140 throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());
141 }
142
3108d502 143 char lc=dns_tolower(str[str.length()-1]);
125e4840
BH
144 if(!isdigit(lc))
145 switch(lc) {
3108d502 146 case 's':
2326ec3f 147 break;
3108d502 148 case 'm':
38e655b6
BH
149 val*=60; // minutes, not months!
150 break;
3108d502 151 case 'h':
125e4840
BH
152 val*=3600;
153 break;
3108d502 154 case 'd':
125e4840
BH
155 val*=3600*24;
156 break;
3108d502 157 case 'w':
125e4840
BH
158 val*=3600*24*7;
159 break;
3108d502 160 case 'y': // ? :-)
125e4840
BH
161 val*=3600*24*365;
162 break;
cfe397d5 163
125e4840 164 default:
3fed7dbd 165 throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());
125e4840
BH
166 }
167 return val;
168}
169
2e83ba09
BH
170bool ZoneParserTNG::getTemplateLine()
171{
9da7b2be
RG
172 if (d_templateparts.empty() || d_templateCounterWrapped || d_templatecounter > d_templatestop) {
173 // no template, or done with
2e83ba09 174 return false;
9da7b2be 175 }
2e83ba09
BH
176
177 string retline;
78924ce1
AV
178 for (auto iter = d_templateparts.begin() ; iter != d_templateparts.end(); ++iter) {
179 if(iter != d_templateparts.begin()) {
180 retline += " ";
181 }
2e83ba09
BH
182
183 string part=makeString(d_templateline, *iter);
1e05b07c
FM
184
185 /* a part can contain a 'naked' $, an escaped $ (\$), or ${offset,width,radix}, with width defaulting to 0,
1817fef6 186 and radix being 'd', 'o', 'x' or 'X', defaulting to 'd' (so ${offset} is valid).
2e83ba09 187
1817fef6 188 The width is zero-padded, so if the counter is at 1, the offset is 15, width is 3, and the radix is 'x',
2e83ba09
BH
189 output will be '010', from the input of ${15,3,x}
190 */
191
192 string outpart;
193 outpart.reserve(part.size()+5);
194 bool inescape=false;
195
196 for(string::size_type pos = 0; pos < part.size() ; ++pos) {
197 char c=part[pos];
198 if(inescape) {
4957a608
BH
199 outpart.append(1, c);
200 inescape=false;
201 continue;
2e83ba09 202 }
1e05b07c 203
2e83ba09 204 if(part[pos]=='\\') {
4957a608
BH
205 inescape=true;
206 continue;
2e83ba09
BH
207 }
208 if(c=='$') {
4957a608 209 if(pos + 1 == part.size() || part[pos+1]!='{') { // a trailing $, or not followed by {
335da0ba 210 outpart.append(std::to_string(d_templatecounter));
4957a608
BH
211 continue;
212 }
1e05b07c
FM
213
214 // need to deal with { case
215
4957a608
BH
216 pos+=2;
217 string::size_type startPos=pos;
218 for(; pos < part.size() && part[pos]!='}' ; ++pos)
219 ;
1e05b07c 220
4957a608
BH
221 if(pos == part.size()) // partial spec
222 break;
223
224 // we are on the '}'
225
226 string spec(part.c_str() + startPos, part.c_str() + pos);
227 int offset=0, width=0;
228 char radix='d';
1817fef6
RG
229 // parse format specifier
230 int extracted = sscanf(spec.c_str(), "%d,%d,%c", &offset, &width, &radix);
231 if (extracted < 1) {
232 throw PDNSException("Unable to parse offset, width and radix for $GENERATE's lhs from '"+spec+"' "+getLineOfFile());
233 }
2651d2f1
RG
234 if (width < 0) {
235 throw PDNSException("Invalid width ("+std::to_string(width)+") for $GENERATE's lhs from '"+spec+"' "+getLineOfFile());
236 }
4957a608 237
4957a608 238 char tmp[80];
ea50e189
RG
239
240 /* a width larger than the output buffer does not make any sense */
241 width = std::min(width, static_cast<int>(sizeof(tmp)));
242
4338e69f
OM
243 switch (radix) {
244 case 'o':
245 snprintf(tmp, sizeof(tmp), "%0*o", width, d_templatecounter + offset);
246 break;
247 case 'x':
248 snprintf(tmp, sizeof(tmp), "%0*x", width, d_templatecounter + offset);
249 break;
250 case 'X':
251 snprintf(tmp, sizeof(tmp), "%0*X", width, d_templatecounter + offset);
252 break;
253 case 'd':
254 default:
255 snprintf(tmp, sizeof(tmp), "%0*d", width, d_templatecounter + offset);
256 break;
257 }
4957a608 258 outpart+=tmp;
2e83ba09
BH
259 }
260 else
4957a608 261 outpart.append(1, c);
2e83ba09
BH
262 }
263 retline+=outpart;
264 }
9da7b2be
RG
265
266 if ((d_templatestop - d_templatecounter) < d_templatestep) {
267 d_templateCounterWrapped = true;
268 }
269 else {
270 d_templatecounter += d_templatestep;
271 }
2e83ba09
BH
272
273 d_line = retline;
274 return true;
275}
276
050e6877 277static void chopComment(string& line)
a09683af 278{
3108d502 279 if(line.find(';')==string::npos)
280 return;
a09683af
BH
281 string::size_type pos, len = line.length();
282 bool inQuote=false;
283 for(pos = 0 ; pos < len; ++pos) {
1e05b07c 284 if(line[pos]=='\\')
a09683af 285 pos++;
1e05b07c 286 else if(line[pos]=='"')
a09683af
BH
287 inQuote=!inQuote;
288 else if(line[pos]==';' && !inQuote)
289 break;
290 }
291 if(pos != len)
292 line.resize(pos);
293}
294
050e6877 295static bool findAndElide(string& line, char c)
9f0076d7
BH
296{
297 string::size_type pos, len = line.length();
298 bool inQuote=false;
299 for(pos = 0 ; pos < len; ++pos) {
1e05b07c 300 if(line[pos]=='\\')
9f0076d7 301 pos++;
1e05b07c 302 else if(line[pos]=='"')
9f0076d7
BH
303 inQuote=!inQuote;
304 else if(line[pos]==c && !inQuote)
305 break;
306 }
307 if(pos != len) {
308 line.erase(pos, 1);
309 return true;
310 }
311 return false;
312}
313
d16a2ccf
PL
314DNSName ZoneParserTNG::getZoneName()
315{
316 return d_zonename;
317}
318
d27ea394
BH
319string ZoneParserTNG::getLineOfFile()
320{
1d830152 321 if (!d_zonedata.empty())
335da0ba 322 return "on line "+std::to_string(std::distance(d_zonedata.begin(), d_zonedataline))+" of given string";
0f0e73fe 323
a1239f65
RG
324 if (d_filestates.empty())
325 return "";
326
335da0ba 327 return "on line "+std::to_string(d_filestates.top().d_lineno)+" of file '"+d_filestates.top().d_filename+"'";
d27ea394 328}
cfe397d5 329
c91effc8 330pair<string,int> ZoneParserTNG::getLineNumAndFile()
331{
9923fc22
PD
332 if (d_filestates.empty())
333 return {"", 0};
334 else
335 return {d_filestates.top().d_filename, d_filestates.top().d_lineno};
c91effc8 336}
337
4950b140 338bool ZoneParserTNG::get(DNSResourceRecord& rr, std::string* comment)
f814d7c8
BH
339{
340 retry:;
2e83ba09 341 if(!getTemplateLine() && !getLine())
f814d7c8 342 return false;
125e4840 343
dc593046 344 boost::trim_right_if(d_line, boost::is_any_of(" \t\r\n\x1a"));
a5a1f447 345 if(comment)
346 comment->clear();
347 if(comment && d_line.find(';') != string::npos)
348 *comment = d_line.substr(d_line.find(';'));
125e4840 349
9bbcf03a
RG
350 d_parts.clear();
351 vstringtok(d_parts, d_line);
352
353 if(d_parts.empty())
125e4840
BH
354 goto retry;
355
9bbcf03a 356 if(d_parts[0].first != d_parts[0].second && d_line[d_parts[0].first]==';') // line consisting of nothing but comments
4d2c97aa
BH
357 goto retry;
358
1e05b07c 359 if(d_line[0]=='$') {
9bbcf03a
RG
360 string command=makeString(d_line, d_parts[0]);
361 if(pdns_iequals(command,"$TTL") && d_parts.size() > 1) {
dc593046 362 d_defaultttl=makeTTLFromZone(trim_right_copy_if(makeString(d_line, d_parts[1]), boost::is_any_of(";")));
df1d406a
BH
363 d_havedollarttl=true;
364 }
9bbcf03a
RG
365 else if(pdns_iequals(command,"$INCLUDE") && d_parts.size() > 1 && d_fromfile) {
366 string fname=unquotify(makeString(d_line, d_parts[1]));
da042e6e 367 if(!fname.empty() && fname[0]!='/' && !d_reldir.empty())
4957a608 368 fname=d_reldir+"/"+fname;
da042e6e 369 stackFile(fname);
bf503cc0 370 }
9bbcf03a
RG
371 else if(pdns_iequals(command, "$ORIGIN") && d_parts.size() > 1) {
372 d_zonename = DNSName(makeString(d_line, d_parts[1]));
2e83ba09 373 }
9bbcf03a 374 else if(pdns_iequals(command, "$GENERATE") && d_parts.size() > 2) {
91a862bf
RG
375 if (!d_generateEnabled) {
376 throw exception("$GENERATE is not allowed in this zone");
377 }
bf503cc0 378 // $GENERATE 1-127 $ CNAME $.0
1817fef6
RG
379 // The range part can be one of two forms: start-stop or start-stop/step. If the first
380 // form is used, then step is set to 1. start, stop and step must be positive
381 // integers between 0 and (2^31)-1. start must not be larger than stop.
9da7b2be
RG
382 // http://www.zytrax.com/books/dns/ch8/generate.html
383 string range = makeString(d_line, d_parts.at(1));
384
385 auto splitOnOnlyOneSeparator = [range](const std::string& input, std::vector<std::string>& output, char separator) {
386 output.clear();
387
388 auto pos = input.find(separator);
389 if (pos == string::npos) {
390 output.emplace_back(input);
391 return;
392 }
393 if (pos == (input.size()-1)) {
394 /* ends on a separator!? */
395 throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
396 }
397 auto next = input.find(separator, pos + 1);
398 if (next != string::npos) {
399 /* more than one separator */
400 throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
401 }
402 output.emplace_back(input.substr(0, pos));
403 output.emplace_back(input.substr(pos + 1));
404 };
405
406 std::vector<std::string> fields;
407 splitOnOnlyOneSeparator(range, fields, '-');
408 if (fields.size() != 2) {
409 throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
410 }
411
412 auto parseValue = [](const std::string& parameters, const std::string& name, const std::string& str, uint32_t& value) {
413 try {
414 auto got = std::stoul(str);
415 if (got > std::numeric_limits<uint32_t>::max()) {
416 throw std::runtime_error("Invalid " + name + " value in $GENERATE parameters '" + parameters + "'");
417 }
418 value = static_cast<uint32_t>(got);
419 }
420 catch (const std::exception& e) {
421 throw std::runtime_error("Invalid " + name + " value in $GENERATE parameters '" + parameters + "': " + e.what());
422 }
423 };
424
425 parseValue(range, "start", fields.at(0), d_templatecounter);
426
427 /* now the remaining part(s) */
428 range = std::move(fields.at(1));
429 splitOnOnlyOneSeparator(range, fields, '/');
430
431 if (fields.size() > 2) {
432 throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
1817fef6 433 }
9da7b2be
RG
434
435 parseValue(range, "stop", fields.at(0), d_templatestop);
436
437 if (fields.size() == 2) {
438 parseValue(range, "step", fields.at(1), d_templatestep);
439 }
440 else {
441 d_templatestep = 1;
1817fef6 442 }
9da7b2be 443
775a673a
OM
444 if (d_templatestep < 1 ||
445 d_templatestop < d_templatecounter) {
9da7b2be 446 throw std::runtime_error("Invalid $GENERATE parameters");
775a673a 447 }
ba3d53d1
RG
448 if (d_maxGenerateSteps != 0) {
449 size_t numberOfSteps = (d_templatestop - d_templatecounter) / d_templatestep;
450 if (numberOfSteps > d_maxGenerateSteps) {
9da7b2be 451 throw std::runtime_error("The number of $GENERATE steps (" + std::to_string(numberOfSteps) + ") is too high, the maximum is set to " + std::to_string(d_maxGenerateSteps));
ba3d53d1
RG
452 }
453 }
9da7b2be
RG
454
455 d_templateline = d_line;
9bbcf03a
RG
456 d_parts.pop_front();
457 d_parts.pop_front();
2e83ba09 458
9da7b2be
RG
459 d_templateparts = d_parts;
460 d_templateCounterWrapped = false;
461
2e83ba09 462 goto retry;
bf503cc0 463 }
125e4840 464 else
d27ea394 465 throw exception("Can't parse zone line '"+d_line+"' "+getLineOfFile());
f814d7c8 466 goto retry;
f814d7c8 467 }
125e4840 468
e720f311 469 bool prevqname=false;
9bbcf03a 470 string qname = makeString(d_line, d_parts[0]); // Don't use DNSName here!
3108d502 471 if(dns_isspace(d_line[0])) {
125e4840 472 rr.qname=d_prevqname;
e720f311
KM
473 prevqname=true;
474 }else {
1e05b07c 475 rr.qname=DNSName(qname);
9bbcf03a 476 d_parts.pop_front();
e720f311 477 if(qname.empty() || qname[0]==';')
125e4840
BH
478 goto retry;
479 }
d66269ef 480 if(qname=="@")
125e4840 481 rr.qname=d_zonename;
e720f311 482 else if(!prevqname && !isCanonical(qname))
675fa24c 483 rr.qname += d_zonename;
125e4840
BH
484 d_prevqname=rr.qname;
485
9bbcf03a 486 if(d_parts.empty())
d27ea394 487 throw exception("Line with too little parts "+getLineOfFile());
125e4840 488
125e4840 489 string nextpart;
1e05b07c 490
125e4840 491 rr.ttl=d_defaultttl;
b4db4fe4
CH
492 bool haveTTL{false}, haveQTYPE{false};
493 string qtypeString;
125e4840
BH
494 pair<string::size_type, string::size_type> range;
495
9bbcf03a
RG
496 while(!d_parts.empty()) {
497 range=d_parts.front();
498 d_parts.pop_front();
125e4840
BH
499 nextpart=makeString(d_line, range);
500 if(nextpart.empty())
501 break;
502
a5a1f447 503 if(nextpart.find(';')!=string::npos) {
125e4840 504 break;
a5a1f447 505 }
125e4840
BH
506
507 // cout<<"Next part: '"<<nextpart<<"'"<<endl;
3108d502 508
509 if(pdns_iequals(nextpart, g_INstr)) {
125e4840
BH
510 // cout<<"Ignoring 'IN'\n";
511 continue;
512 }
cfe397d5 513 if(!haveTTL && !haveQTYPE && isTimeSpec(nextpart)) {
125e4840 514 rr.ttl=makeTTLFromZone(nextpart);
7fd6c67e 515 if(!d_havedollarttl)
516 d_defaultttl = rr.ttl;
125e4840
BH
517 haveTTL=true;
518 // cout<<"ttl is probably: "<<rr.ttl<<endl;
519 continue;
520 }
1e05b07c 521 if(haveQTYPE)
125e4840
BH
522 break;
523
524 try {
b4db4fe4 525 rr.qtype = DNSRecordContent::TypeToNumber(nextpart);
125e4840 526 // cout<<"Got qtype ("<<rr.qtype.getCode()<<")\n";
b4db4fe4
CH
527 qtypeString = nextpart;
528 haveQTYPE = true;
125e4840
BH
529 continue;
530 }
531 catch(...) {
d27ea394 532 throw runtime_error("Parsing zone content "+getLineOfFile()+
232f0877
CH
533 ": '"+nextpart+
534 "' doesn't look like a qtype, stopping loop");
125e4840
BH
535 }
536 }
1e05b07c 537 if(!haveQTYPE)
d27ea394 538 throw exception("Malformed line "+getLineOfFile()+": '"+d_line+"'");
125e4840 539
3108d502 540 // rr.content=d_line.substr(range.first);
541 rr.content.assign(d_line, range.first, string::npos);
a09683af 542 chopComment(rr.content);
dc593046 543 trim_if(rr.content, boost::is_any_of(" \r\n\t\x1a"));
849fde0b 544
3108d502 545 if(rr.content.size()==1 && rr.content[0]=='@')
90c3521b 546 rr.content=d_zonename.toString();
b33702d5 547
9f0076d7
BH
548 if(findAndElide(rr.content, '(')) { // have found a ( and elided it
549 if(!findAndElide(rr.content, ')')) {
550 while(getLine()) {
dc593046 551 boost::trim_right(d_line);
4957a608 552 chopComment(d_line);
dc593046 553 boost::trim(d_line);
1e05b07c 554
4957a608
BH
555 bool ended = findAndElide(d_line, ')');
556 rr.content+=" "+d_line;
557 if(ended)
558 break;
125e4840 559 }
125e4840
BH
560 }
561 }
dc593046 562 boost::trim_if(rr.content, boost::is_any_of(" \r\n\t\x1a"));
9f0076d7 563
b4db4fe4
CH
564 if (d_upgradeContent && DNSRecordContent::isUnknownType(qtypeString)) {
565 rr.content = DNSRecordContent::upgradeContent(rr.qname, rr.qtype, rr.content);
566 }
567
43f40013 568 vector<string> recparts;
125e4840
BH
569 switch(rr.qtype.getCode()) {
570 case QType::MX:
43f40013
BH
571 stringtok(recparts, rr.content);
572 if(recparts.size()==2) {
1293f91e
PL
573 if (recparts[1]!=".") {
574 try {
575 recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot();
576 } catch (std::exception &e) {
d5fcd583 577 throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
1293f91e
PL
578 }
579 }
43f40013
BH
580 rr.content=recparts[0]+" "+recparts[1];
581 }
582 break;
1e05b07c 583
6348d406
PD
584 case QType::RP:
585 stringtok(recparts, rr.content);
586 if(recparts.size()==2) {
0c0e717c
PD
587 recparts[0] = toCanonic(d_zonename, recparts[0]).toStringRootDot();
588 recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot();
6348d406
PD
589 rr.content=recparts[0]+" "+recparts[1];
590 }
591 break;
592
25e0cd7f
BH
593 case QType::SRV:
594 stringtok(recparts, rr.content);
595 if(recparts.size()==4) {
1293f91e
PL
596 if(recparts[3]!=".") {
597 try {
598 recparts[3] = toCanonic(d_zonename, recparts[3]).toStringRootDot();
599 } catch (std::exception &e) {
d5fcd583 600 throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
1293f91e
PL
601 }
602 }
25e0cd7f
BH
603 rr.content=recparts[0]+" "+recparts[1]+" "+recparts[2]+" "+recparts[3];
604 }
605 break;
1e05b07c
FM
606
607
125e4840
BH
608 case QType::NS:
609 case QType::CNAME:
8dee0750 610 case QType::DNAME:
125e4840 611 case QType::PTR:
1293f91e
PL
612 try {
613 rr.content = toCanonic(d_zonename, rr.content).toStringRootDot();
614 } catch (std::exception &e) {
d5fcd583 615 throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
1293f91e 616 }
125e4840 617 break;
319d6e47 618 case QType::AFSDB:
9f067a15
JJ
619 stringtok(recparts, rr.content);
620 if(recparts.size() == 2) {
621 try {
319d6e47 622 recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot();
9f067a15 623 } catch (std::exception &e) {
d5fcd583 624 throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
319d6e47 625 }
9f067a15 626 } else {
86f1af1c 627 throw PDNSException("AFSDB record for "+rr.qname.toLogString()+" invalid");
9f067a15
JJ
628 }
629 rr.content.clear();
630 for(string::size_type n = 0; n < recparts.size(); ++n) {
eb914147 631 if (n != 0) {
9f067a15 632 rr.content.append(1,' ');
eb914147 633 }
125e4840 634
9f067a15 635 rr.content+=recparts[n];
319d6e47
JJ
636 }
637 break;
125e4840 638 case QType::SOA:
43f40013 639 stringtok(recparts, rr.content);
0c306c7c 640 if(recparts.size() > 7)
86f1af1c 641 throw PDNSException("SOA record contents for "+rr.qname.toLogString()+" contains too many parts");
43f40013 642 if(recparts.size() > 1) {
562c0b13
PL
643 try {
644 recparts[0]=toCanonic(d_zonename, recparts[0]).toStringRootDot();
645 recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot();
1293f91e 646 } catch (std::exception &e) {
d5fcd583 647 throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
562c0b13 648 }
125e4840
BH
649 }
650 rr.content.clear();
43f40013 651 for(string::size_type n = 0; n < recparts.size(); ++n) {
eb914147 652 if (n != 0) {
4957a608 653 rr.content.append(1,' ');
eb914147 654 }
c9f935fa 655
82cc6877 656 if(n > 1)
335da0ba 657 rr.content+=std::to_string(makeTTLFromZone(recparts[n]));
82cc6877 658 else
43f40013 659 rr.content+=recparts[n];
125e4840 660 }
38e655b6 661 break;
125e4840
BH
662 default:;
663 }
f814d7c8
BH
664 return true;
665}
666
834942f1 667
f814d7c8
BH
668bool ZoneParserTNG::getLine()
669{
1d830152 670 if (!d_zonedata.empty()) {
0f0e73fe
MS
671 if (d_zonedataline != d_zonedata.end()) {
672 d_line = *d_zonedataline;
cb6655e7 673 ++d_zonedataline;
0f0e73fe
MS
674 return true;
675 }
676 return false;
677 }
cfe397d5 678 while(!d_filestates.empty()) {
834942f1 679 if(stringfgets(d_filestates.top().d_fp, d_line)) {
cfe397d5 680 d_filestates.top().d_lineno++;
bf503cc0
BH
681 return true;
682 }
cfe397d5
BH
683 fclose(d_filestates.top().d_fp);
684 d_filestates.pop();
f814d7c8
BH
685 }
686 return false;
687}