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