• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 18409242756

10 Oct 2025 02:16PM UTC coverage: 19.38% (-44.8%) from 64.13%
18409242756

push

github

web-flow
Merge pull request #16245 from miodvallat/matriochka_exception

auth: yet another logic botch

3972 of 30808 branches covered (12.89%)

Branch coverage included in aggregate %.

11562 of 49346 relevant lines covered (23.43%)

3168.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pdns/zoneparser-tng.cc
1
/*
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
 */
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
#include "dnsparser.hh"
26
#include "sstuff.hh"
27
#include "misc.hh"
28
#include "dnswriter.hh"
29
#include "dnsrecords.hh"
30
#include <fstream>
31
#include "dns.hh"
32
#include "zoneparser-tng.hh"
33
#include <deque>
34
#include <boost/algorithm/string.hpp>
35
#include <system_error>
36
#include <cinttypes>
37
#include <sys/stat.h>
38

39
const static string g_INstr("IN");
40

41
ZoneParserTNG::ZoneParserTNG(const string& fname, ZoneName zname, string reldir, bool upgradeContent):
42
  d_reldir(std::move(reldir)), d_zonename(std::move(zname)), d_defaultttl(3600),
43
  d_templatecounter(0), d_templatestop(0), d_templatestep(0),
44
  d_havespecificttl(false), d_fromfile(true), d_upgradeContent(upgradeContent)
45
{
×
46
  stackFile(fname);
×
47
}
×
48

49
ZoneParserTNG::ZoneParserTNG(const vector<string>& zonedata, ZoneName zname, bool upgradeContent):
50
  d_zonename(std::move(zname)), d_zonedata(zonedata), d_defaultttl(3600),
51
  d_templatecounter(0), d_templatestop(0), d_templatestep(0),
52
  d_havespecificttl(false), d_fromfile(false), d_upgradeContent(upgradeContent)
53
{
×
54
  d_zonedataline = d_zonedata.begin();
×
55
}
×
56

57
void ZoneParserTNG::stackFile(const std::string& fname)
58
{
×
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

70
  struct stat st = {};
×
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");
×
83
  if (fp == nullptr) {
×
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));
×
88
  }
×
89

90
  filestate fs(fp, fname);
×
91
  d_filestates.push(fs);
×
92
  d_fromfile = true;
×
93
  d_fileset.emplace_back(std::make_pair(fname, st.st_ctime));
×
94
}
×
95

96
ZoneParserTNG::~ZoneParserTNG()
97
{
×
98
  while(!d_filestates.empty()) {
×
99
    fclose(d_filestates.top().d_fp);
×
100
    d_filestates.pop();
×
101
  }
×
102
}
×
103

104
static string makeString(const string& line, const pair<string::size_type, string::size_type>& range)
105
{
×
106
  return string(line.c_str() + range.first, range.second - range.first);
×
107
}
×
108

109
static bool isTimeSpec(const string& nextpart)
110
{
×
111
  if (nextpart.empty()) {
×
112
    return false;
×
113
  }
×
114

115
  for (auto iter = nextpart.begin(); iter != nextpart.end(); ++iter) {
×
116
    auto current = static_cast<unsigned char>(*iter);
×
117
    if (isdigit(current) != 0) {
×
118
      continue;
×
119
    }
×
120

121
    if (iter + 1 != nextpart.end()) {
×
122
      return false;
×
123
    }
×
124

125
    char c = static_cast<char>(tolower(current));
×
126
    return (c=='s' || c=='m' || c=='h' || c=='d' || c=='w' || c=='y');
×
127
  }
×
128
  return true;
×
129
}
×
130

131

132
unsigned int ZoneParserTNG::makeTTLFromZone(const string& str)
133
{
×
134
  if(str.empty())
×
135
    return 0;
×
136

137
  unsigned int val = 0;
×
138
  try {
×
139
    pdns::checked_stoi_into(val, str);
×
140
  }
×
141
  catch (const std::out_of_range& oor) {
×
142
    throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());
×
143
  }
×
144

145
  char lc=dns_tolower(str[str.length()-1]);
×
146
  if(!isdigit(lc))
×
147
    switch(lc) {
×
148
    case 's':
×
149
      break;
×
150
    case 'm':
×
151
      val*=60; // minutes, not months!
×
152
      break;
×
153
    case 'h':
×
154
      val*=3600;
×
155
      break;
×
156
    case 'd':
×
157
      val*=3600*24;
×
158
      break;
×
159
    case 'w':
×
160
      val*=3600*24*7;
×
161
      break;
×
162
    case 'y': // ? :-)
×
163
      val*=3600*24*365;
×
164
      break;
×
165

166
    default:
×
167
      throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());
×
168
    }
×
169
  return val;
×
170
}
×
171

172
bool ZoneParserTNG::getTemplateLine()
173
{
×
174
  if (d_templateparts.empty() || d_templateCounterWrapped || d_templatecounter > d_templatestop) {
×
175
    // no template, or done with
176
    return false;
×
177
  }
×
178

179
  string retline;
×
180
  for (auto iter = d_templateparts.begin() ; iter != d_templateparts.end(); ++iter) {
×
181
    if(iter != d_templateparts.begin()) {
×
182
      retline += " ";
×
183
    }
×
184

185
    string part=makeString(d_templateline, *iter);
×
186

187
    /* a part can contain a 'naked' $, an escaped $ (\$), or ${offset,width,radix}, with width defaulting to 0,
188
       and radix being 'd', 'o', 'x' or 'X', defaulting to 'd' (so ${offset} is valid).
189

190
       The width is zero-padded, so if the counter is at 1, the offset is 15, width is 3, and the radix is 'x',
191
       output will be '010', from the input of ${15,3,x}
192
    */
193

194
    string outpart;
×
195
    outpart.reserve(part.size()+5);
×
196
    bool inescape=false;
×
197

198
    for(string::size_type pos = 0; pos < part.size() ; ++pos) {
×
199
      char c=part[pos];
×
200
      if(inescape) {
×
201
        outpart.append(1, c);
×
202
        inescape=false;
×
203
        continue;
×
204
      }
×
205

206
      if(part[pos]=='\\') {
×
207
        inescape=true;
×
208
        continue;
×
209
      }
×
210
      if(c=='$') {
×
211
        if(pos + 1 == part.size() || part[pos+1]!='{') {  // a trailing $, or not followed by {
×
212
          outpart.append(std::to_string(d_templatecounter));
×
213
          continue;
×
214
        }
×
215

216
        // need to deal with { case
217

218
        pos+=2;
×
219
        string::size_type startPos=pos;
×
220
        for(; pos < part.size() && part[pos]!='}' ; ++pos)
×
221
          ;
×
222

223
        if(pos == part.size()) // partial spec
×
224
          break;
×
225

226
        // we are on the '}'
227

228
        string spec(part.c_str() + startPos, part.c_str() + pos);
×
229
        int offset=0, width=0;
×
230
        char radix='d';
×
231
        // parse format specifier
232
        int extracted = sscanf(spec.c_str(), "%d,%d,%c", &offset, &width, &radix);
×
233
        if (extracted < 1) {
×
234
          throw PDNSException("Unable to parse offset, width and radix for $GENERATE's lhs from '"+spec+"' "+getLineOfFile());
×
235
        }
×
236
        if (width < 0) {
×
237
          throw PDNSException("Invalid width ("+std::to_string(width)+") for $GENERATE's lhs from '"+spec+"' "+getLineOfFile());
×
238
        }
×
239

240
        char tmp[80];
×
241

242
        /* a width larger than the output buffer does not make any sense */
243
        width = std::min(width, static_cast<int>(sizeof(tmp)));
×
244

245
        switch (radix) {
×
246
        case 'o':
×
247
          snprintf(tmp, sizeof(tmp), "%0*o", width, d_templatecounter + offset);
×
248
          break;
×
249
        case 'x':
×
250
          snprintf(tmp, sizeof(tmp), "%0*x", width, d_templatecounter + offset);
×
251
          break;
×
252
        case 'X':
×
253
          snprintf(tmp, sizeof(tmp), "%0*X", width, d_templatecounter + offset);
×
254
          break;
×
255
        case 'd':
×
256
        default:
×
257
          snprintf(tmp, sizeof(tmp), "%0*d", width, d_templatecounter + offset);
×
258
          break;
×
259
        }
×
260
        outpart+=tmp;
×
261
      }
×
262
      else
×
263
        outpart.append(1, c);
×
264
    }
×
265
    retline+=outpart;
×
266
  }
×
267

268
  if ((d_templatestop - d_templatecounter) < d_templatestep) {
×
269
    d_templateCounterWrapped = true;
×
270
  }
×
271
  else {
×
272
    d_templatecounter += d_templatestep;
×
273
  }
×
274

275
  d_line = std::move(retline);
×
276
  return true;
×
277
}
×
278

279
static void chopComment(string& line)
280
{
×
281
  if(line.find(';')==string::npos)
×
282
    return;
×
283

284
  string::size_type pos = 0;
×
285
  auto len = line.length();
×
286
  bool inQuote = false;
×
287
  for(; pos < len; ++pos) {
×
288
    if(line[pos]=='\\')
×
289
      pos++;
×
290
    else if(line[pos]=='"')
×
291
      inQuote=!inQuote;
×
292
    else if(line[pos]==';' && !inQuote)
×
293
      break;
×
294
  }
×
295
  if(pos != len)
×
296
    line.resize(pos);
×
297
}
×
298

299
static bool findAndElide(string& line, char c)
300
{
×
301
  string::size_type pos, len = line.length();
×
302
  bool inQuote=false;
×
303
  for(pos = 0 ; pos < len; ++pos) {
×
304
    if(line[pos]=='\\')
×
305
      pos++;
×
306
    else if(line[pos]=='"')
×
307
      inQuote=!inQuote;
×
308
    else if(line[pos]==c && !inQuote)
×
309
      break;
×
310
  }
×
311
  if(pos != len) {
×
312
    line.erase(pos, 1);
×
313
    return true;
×
314
  }
×
315
  return false;
×
316
}
×
317

318
ZoneName ZoneParserTNG::getZoneName()
319
{
×
320
  return d_zonename;
×
321
}
×
322

323
string ZoneParserTNG::getLineOfFile()
324
{
×
325
  if (!d_zonedata.empty())
×
326
    return "on line "+std::to_string(std::distance(d_zonedata.begin(), d_zonedataline))+" of given string";
×
327

328
  if (d_filestates.empty())
×
329
    return "";
×
330

331
  return "on line "+std::to_string(d_filestates.top().d_lineno)+" of file '"+d_filestates.top().d_filename+"'";
×
332
}
×
333

334
pair<string,int> ZoneParserTNG::getLineNumAndFile()
335
{
×
336
  if (d_filestates.empty())
×
337
    return {"", 0};
×
338
  else
×
339
    return {d_filestates.top().d_filename, d_filestates.top().d_lineno};
×
340
}
×
341

342
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
343
bool ZoneParserTNG::get(DNSResourceRecord& rr, std::string* comment)
344
{
×
345
 retry:;
×
346
  if(!getTemplateLine() && !getLine())
×
347
    return false;
×
348

349
  boost::trim_right_if(d_line, boost::is_any_of(" \t\r\n\x1a"));
×
350
  if(comment)
×
351
    comment->clear();
×
352
  if(comment && d_line.find(';') != string::npos)
×
353
    *comment = d_line.substr(d_line.find(';'));
×
354

355
  d_parts.clear();
×
356
  vstringtok(d_parts, d_line);
×
357

358
  if(d_parts.empty())
×
359
    goto retry;
×
360

361
  if(d_parts[0].first != d_parts[0].second && d_line[d_parts[0].first]==';') // line consisting of nothing but comments
×
362
    goto retry;
×
363

364
  if(d_line[0]=='$') {
×
365
    string command=makeString(d_line, d_parts[0]);
×
366
    if(pdns_iequals(command,"$TTL") && d_parts.size() > 1) {
×
367
      d_defaultttl=makeTTLFromZone(trim_right_copy_if(makeString(d_line, d_parts[1]), boost::is_any_of(";")));
×
368
      d_havespecificttl=true;
×
369
    }
×
370
    else if(pdns_iequals(command,"$INCLUDE") && d_parts.size() > 1 && d_fromfile) {
×
371
      string fname=unquotify(makeString(d_line, d_parts[1]));
×
372
      // Find the first semicolon and remove everything after it, including the semicolon
373
      if (auto semicolon_pos = fname.find(';'); semicolon_pos != string::npos) {
×
374
        fname.resize(semicolon_pos);
×
375
      }
×
376
      if (!fname.empty() && fname[0] != '/' && !d_reldir.empty()) {
×
377
        fname = d_reldir + "/" + fname;
×
378
      }
×
379
      stackFile(fname);
×
380
    }
×
381
    else if(pdns_iequals(command, "$ORIGIN") && d_parts.size() > 1) {
×
382
      d_zonename = ZoneName(makeString(d_line, d_parts[1]));
×
383
    }
×
384
    else if(pdns_iequals(command, "$GENERATE") && d_parts.size() > 2) {
×
385
      if (!d_generateEnabled) {
×
386
        throw exception("$GENERATE is not allowed in this zone");
×
387
      }
×
388
      // $GENERATE 1-127 $ CNAME $.0
389
      // The range part can be one of two forms: start-stop or start-stop/step. If the first
390
      // form is used, then step is set to 1. start, stop and step must be positive
391
      // integers between 0 and (2^31)-1. start must not be larger than stop.
392
      // http://www.zytrax.com/books/dns/ch8/generate.html
393
      string range = makeString(d_line, d_parts.at(1));
×
394

395
      auto splitOnOnlyOneSeparator = [range](const std::string& input, std::vector<std::string>& output, char separator) {
×
396
        output.clear();
×
397

398
        auto pos = input.find(separator);
×
399
        if (pos == string::npos) {
×
400
          output.emplace_back(input);
×
401
          return;
×
402
        }
×
403
        if (pos == (input.size()-1)) {
×
404
          /* ends on a separator!? */
405
          throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
×
406
        }
×
407
        auto next = input.find(separator, pos + 1);
×
408
        if (next != string::npos) {
×
409
          /* more than one separator */
410
          throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
×
411
        }
×
412
        output.emplace_back(input.substr(0, pos));
×
413
        output.emplace_back(input.substr(pos + 1));
×
414
      };
×
415

416
      std::vector<std::string> fields;
×
417
      splitOnOnlyOneSeparator(range, fields, '-');
×
418
      if (fields.size() != 2) {
×
419
        throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
×
420
      }
×
421

422
      auto parseValue = [](const std::string& parameters, const std::string& name, const std::string& str, uint32_t& value) {
×
423
        try {
×
424
          auto got = std::stoul(str);
×
425
          if (got > std::numeric_limits<uint32_t>::max()) {
×
426
            throw std::runtime_error("Invalid " + name + " value in $GENERATE parameters '" + parameters + "'");
×
427
          }
×
428
          value = static_cast<uint32_t>(got);
×
429
        }
×
430
        catch (const std::exception& e) {
×
431
          throw std::runtime_error("Invalid " + name + " value in $GENERATE parameters '" + parameters + "': " + e.what());
×
432
        }
×
433
      };
×
434

435
      parseValue(range, "start", fields.at(0), d_templatecounter);
×
436

437
      /* now the remaining part(s) */
438
      range = std::move(fields.at(1));
×
439
      splitOnOnlyOneSeparator(range, fields, '/');
×
440

441
      if (fields.size() > 2) {
×
442
        throw std::runtime_error("Invalid range from $GENERATE parameters '" + range + "'");
×
443
      }
×
444

445
      parseValue(range, "stop", fields.at(0), d_templatestop);
×
446

447
      if (fields.size() == 2) {
×
448
        parseValue(range, "step", fields.at(1), d_templatestep);
×
449
      }
×
450
      else {
×
451
        d_templatestep = 1;
×
452
      }
×
453

454
      if (d_templatestep < 1 ||
×
455
          d_templatestop < d_templatecounter) {
×
456
        throw std::runtime_error("Invalid $GENERATE parameters");
×
457
      }
×
458
      if (d_maxGenerateSteps != 0) {
×
459
        size_t numberOfSteps = (d_templatestop - d_templatecounter) / d_templatestep;
×
460
        if (numberOfSteps > d_maxGenerateSteps) {
×
461
          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));
×
462
        }
×
463
      }
×
464

465
      d_templateline = d_line;
×
466
      d_parts.pop_front();
×
467
      d_parts.pop_front();
×
468

469
      d_templateparts = d_parts;
×
470
      d_templateCounterWrapped = false;
×
471

472
      goto retry;
×
473
    }
×
474
    else
×
475
      throw exception("Can't parse zone line '"+d_line+"' "+getLineOfFile());
×
476
    goto retry;
×
477
  }
×
478

479
  bool prevqname=false;
×
480
  string qname = makeString(d_line, d_parts[0]); // Don't use DNSName here!
×
481
  if(dns_isspace(d_line[0])) {
×
482
    rr.qname=d_prevqname;
×
483
    prevqname=true;
×
484
  }else {
×
485
    rr.qname=DNSName(qname);
×
486
    d_parts.pop_front();
×
487
    if(qname.empty() || qname[0]==';')
×
488
      goto retry;
×
489
  }
×
490
  if(qname=="@")
×
491
    rr.qname=DNSName(d_zonename);
×
492
  else if(!prevqname && !isCanonical(qname))
×
493
    rr.qname += DNSName(d_zonename);
×
494
  d_prevqname=rr.qname;
×
495

496
  if(d_parts.empty())
×
497
    throw exception("Line with too little parts "+getLineOfFile());
×
498

499
  string nextpart;
×
500

501
  rr.ttl=d_defaultttl;
×
502
  bool haveTTL{false}, haveQTYPE{false};
×
503
  string qtypeString;
×
504
  pair<string::size_type, string::size_type> range;
×
505

506
  while(!d_parts.empty()) {
×
507
    range=d_parts.front();
×
508
    d_parts.pop_front();
×
509
    nextpart=makeString(d_line, range);
×
510
    if(nextpart.empty())
×
511
      break;
×
512

513
    if(nextpart.find(';')!=string::npos) {
×
514
      break;
×
515
    }
×
516

517
    // cout<<"Next part: '"<<nextpart<<"'"<<endl;
518

519
    if(pdns_iequals(nextpart, g_INstr)) {
×
520
      // cout<<"Ignoring 'IN'\n";
521
      continue;
×
522
    }
×
523
    if(!haveTTL && !haveQTYPE && isTimeSpec(nextpart)) {
×
524
      rr.ttl=makeTTLFromZone(nextpart);
×
525
      if (!d_havespecificttl) {
×
526
        d_defaultttl = rr.ttl;
×
527
      }
×
528
      haveTTL=true;
×
529
      // cout<<"ttl is probably: "<<rr.ttl<<endl;
530
      continue;
×
531
    }
×
532
    if(haveQTYPE)
×
533
      break;
×
534

535
    try {
×
536
      rr.qtype = DNSRecordContent::TypeToNumber(nextpart);
×
537
      // cout<<"Got qtype ("<<rr.qtype.getCode()<<")\n";
538
      qtypeString = nextpart;
×
539
      haveQTYPE = true;
×
540
      continue;
×
541
    }
×
542
    catch(...) {
×
543
      throw runtime_error("Parsing zone content "+getLineOfFile()+
×
544
                          ": '"+nextpart+
×
545
                          "' doesn't look like a qtype, stopping loop");
×
546
    }
×
547
  }
×
548
  if(!haveQTYPE)
×
549
    throw exception("Malformed line "+getLineOfFile()+": '"+d_line+"'");
×
550

551
  //  rr.content=d_line.substr(range.first);
552
  rr.content.assign(d_line, range.first, string::npos);
×
553
  chopComment(rr.content);
×
554
  trim_if(rr.content, boost::is_any_of(" \r\n\t\x1a"));
×
555

556
  if(rr.content.size()==1 && rr.content[0]=='@')
×
557
    rr.content=DNSName(d_zonename).toString();
×
558

559
  if(findAndElide(rr.content, '(')) {      // have found a ( and elided it
×
560
    if(!findAndElide(rr.content, ')')) {
×
561
      while(getLine()) {
×
562
        boost::trim_right(d_line);
×
563
        chopComment(d_line);
×
564
        boost::trim(d_line);
×
565

566
        bool ended = findAndElide(d_line, ')');
×
567
        rr.content+=" "+d_line;
×
568
        if(ended)
×
569
          break;
×
570
      }
×
571
    }
×
572
  }
×
573
  boost::trim_if(rr.content, boost::is_any_of(" \r\n\t\x1a"));
×
574

575
  if (d_upgradeContent && DNSRecordContent::isUnknownType(qtypeString)) {
×
576
    rr.content = DNSRecordContent::upgradeContent(rr.qname, rr.qtype, rr.content);
×
577
  }
×
578

579
  vector<string> recparts;
×
580
  switch(rr.qtype.getCode()) {
×
581
  case QType::MX:
×
582
    stringtok(recparts, rr.content);
×
583
    if(recparts.size()==2) {
×
584
      if (recparts[1]!=".") {
×
585
        try {
×
586
          recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot();
×
587
        } catch (std::exception &e) {
×
588
          throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
×
589
        }
×
590
      }
×
591
      rr.content=recparts[0]+" "+recparts[1];
×
592
    }
×
593
    break;
×
594

595
  case QType::RP:
×
596
    stringtok(recparts, rr.content);
×
597
    if(recparts.size()==2) {
×
598
      recparts[0] = toCanonic(d_zonename, recparts[0]).toStringRootDot();
×
599
      recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot();
×
600
      rr.content=recparts[0]+" "+recparts[1];
×
601
    }
×
602
    break;
×
603

604
  case QType::SRV:
×
605
    stringtok(recparts, rr.content);
×
606
    if(recparts.size()==4) {
×
607
      if(recparts[3]!=".") {
×
608
        try {
×
609
          recparts[3] = toCanonic(d_zonename, recparts[3]).toStringRootDot();
×
610
        } catch (std::exception &e) {
×
611
          throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
×
612
        }
×
613
      }
×
614
      rr.content=recparts[0]+" "+recparts[1]+" "+recparts[2]+" "+recparts[3];
×
615
    }
×
616
    break;
×
617

618
#if !defined(RECURSOR)
619
  case QType::ALIAS:
620
#endif
621
  case QType::NS:
×
622
  case QType::CNAME:
×
623
  case QType::DNAME:
×
624
  case QType::PTR:
×
625
    try {
×
626
      rr.content = toCanonic(d_zonename, rr.content).toStringRootDot();
×
627
    } catch (std::exception &e) {
×
628
      throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
×
629
    }
×
630
    break;
×
631
  case QType::AFSDB:
×
632
    stringtok(recparts, rr.content);
×
633
    if(recparts.size() == 2) {
×
634
      try {
×
635
        recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot();
×
636
      } catch (std::exception &e) {
×
637
        throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
×
638
      }
×
639
    } else {
×
640
      throw PDNSException("AFSDB record for "+rr.qname.toLogString()+" invalid");
×
641
    }
×
642
    rr.content.clear();
×
643
    for(string::size_type n = 0; n < recparts.size(); ++n) {
×
644
      if (n != 0) {
×
645
        rr.content.append(1,' ');
×
646
      }
×
647

648
      rr.content+=recparts[n];
×
649
    }
×
650
    break;
×
651
  case QType::SOA:
×
652
    stringtok(recparts, rr.content);
×
653
    if(recparts.size() > 7)
×
654
      throw PDNSException("SOA record contents for "+rr.qname.toLogString()+" contains too many parts");
×
655
    if(recparts.size() > 1) {
×
656
      try {
×
657
        recparts[0]=toCanonic(d_zonename, recparts[0]).toStringRootDot();
×
658
        recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot();
×
659
      } catch (std::exception &e) {
×
660
        throw PDNSException("Error in record '" + rr.qname.toLogString() + " " + rr.qtype.toString() + "': " + e.what());
×
661
      }
×
662
    }
×
663
    rr.content.clear();
×
664
    for(string::size_type n = 0; n < recparts.size(); ++n) {
×
665
      if (n != 0) {
×
666
        rr.content.append(1,' ');
×
667
      }
×
668

669
      if(n > 1)
×
670
        rr.content+=std::to_string(makeTTLFromZone(recparts[n]));
×
671
      else
×
672
        rr.content+=recparts[n];
×
673
    }
×
674
    break;
×
675
  default:;
×
676
  }
×
677
  return true;
×
678
}
×
679

680

681
bool ZoneParserTNG::getLine()
682
{
×
683
  if (!d_zonedata.empty()) {
×
684
    if (d_zonedataline != d_zonedata.end()) {
×
685
      d_line = *d_zonedataline;
×
686
      ++d_zonedataline;
×
687
      return true;
×
688
    }
×
689
    return false;
×
690
  }
×
691
  while(!d_filestates.empty()) {
×
692
    if(stringfgets(d_filestates.top().d_fp, d_line)) {
×
693
      d_filestates.top().d_lineno++;
×
694
      return true;
×
695
    }
×
696
    fclose(d_filestates.top().d_fp);
×
697
    d_filestates.pop();
×
698
  }
×
699
  return false;
×
700
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc