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

PowerDNS / pdns / 18937558685

30 Oct 2025 10:27AM UTC coverage: 73.04% (+0.03%) from 73.014%
18937558685

Pull #16395

github

web-flow
Merge 3b9be1959 into 9769584db
Pull Request #16395: dnsdist: Add option to use incoming OpenTelemetry Trace ID

38333 of 63186 branches covered (60.67%)

Branch coverage included in aggregate %.

109 of 120 new or added lines in 5 files covered. (90.83%)

64 existing lines in 15 files now uncovered.

127583 of 163972 relevant lines covered (77.81%)

5996675.21 hits per line

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

67.34
/pdns/axfr-retriever.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

23
#include "axfr-retriever.hh"
24
#include "arguments.hh"
25
#include "dns_random.hh"
26
#include "utility.hh"
27
#include "resolver.hh"
28
#include "query-local-address.hh"
29

30
using pdns::resolver::parseResult;
31

32
AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
33
                             const ZoneName& domain,
34
                             const TSIGTriplet& tsigConf,
35
                             const ComboAddress* laddr,
36
                             size_t maxReceivedBytes,
37
                             uint16_t timeout) :
38
  d_buf(65536), d_tsigVerifier(tsigConf, remote, d_trc), d_maxReceivedBytes(maxReceivedBytes)
39
{
467✔
40
  ComboAddress local;
467✔
41
  if (laddr != nullptr) {
467!
42
    local = ComboAddress(*laddr);
467✔
43
  } else {
467✔
UNCOV
44
    if (!pdns::isQueryLocalAddressFamilyEnabled(remote.sin4.sin_family)) {
×
45
      throw ResolverException("Unable to determine source address for AXFR request to " + remote.toStringWithPort() + " for " + domain.toLogString() + ". Address family is not configured for outgoing queries");
×
46
    }
×
UNCOV
47
    local = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
×
UNCOV
48
  }
×
49
  d_sock = -1;
467✔
50
  try {
467✔
51
    d_sock = makeQuerySocket(local, false); // make a TCP socket
467✔
52
    if (d_sock < 0)
467!
53
      throw ResolverException("Error creating socket for AXFR request to "+d_remote.toStringWithPort());
×
54

55
    d_remote = remote; // mostly for error reporting
467✔
56
    this->connect(timeout);
467✔
57
    d_soacount = 0;
467✔
58
  
59
    vector<uint8_t> packet;
467✔
60
    DNSPacketWriter pwriter(packet, DNSName(domain), QType::AXFR);
467✔
61
    pwriter.getHeader()->id = dns_random_uint16();
467✔
62

63
    if (!tsigConf.name.empty()) {
467✔
64
      if (tsigConf.algo == g_hmacmd5dnsname) {
23!
65
        d_trc.d_algoName = g_hmacmd5dnsname_long;
23✔
66
      }
23✔
67
      else {
×
68
        d_trc.d_algoName = tsigConf.algo;
×
69
      }
×
70
      d_trc.d_time = time(nullptr);
23✔
71
      d_trc.d_fudge = 300;
23✔
72
      d_trc.d_origID=ntohs(pwriter.getHeader()->id);
23✔
73
      d_trc.d_eRcode=0;
23✔
74
      addTSIG(pwriter, d_trc, tsigConf.name, tsigConf.secret, "", false);
23✔
75
    }
23✔
76
  
77
    uint16_t replen=htons(packet.size());
467✔
78
    Utility::iovec iov[2];
467✔
79
    iov[0].iov_base=reinterpret_cast<char*>(&replen);
467✔
80
    iov[0].iov_len=2;
467✔
81
    iov[1].iov_base=packet.data();
467✔
82
    iov[1].iov_len=packet.size();
467✔
83
  
84
    int ret=Utility::writev(d_sock, iov, 2);
467✔
85
    if(ret < 0)
467!
86
      throw ResolverException("Error sending question to "+d_remote.toStringWithPort()+": "+stringerror());
×
87
    if(ret != (int)(2+packet.size())) {
467!
88
      throw ResolverException("Partial write on AXFR request to "+d_remote.toStringWithPort());
×
89
    }
×
90
  
91
    int res = waitForData(d_sock, timeout, 0);
467✔
92
    
93
    if(!res)
467!
94
      throw ResolverException("Timeout waiting for answer from "+d_remote.toStringWithPort()+" during AXFR");
×
95
    if(res<0)
467!
96
      throw ResolverException("Error waiting for answer from "+d_remote.toStringWithPort()+": "+stringerror());
×
97
  }
467✔
98
  catch(...) {
467✔
99
    if(d_sock >= 0)
3!
100
      close(d_sock);
3✔
101
    d_sock = -1;
3✔
102
    throw;
3✔
103
  }
3✔
104
}
467✔
105

106
AXFRRetriever::~AXFRRetriever()
107
{
464✔
108
  close(d_sock);
464✔
109
}
464✔
110

111

112

113
int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records, uint16_t timeout) // Implementation is making sure RFC2845 4.4 is followed.
114
{
20,237✔
115
  if(d_soacount > 1)
20,237✔
116
    return false;
461✔
117

118
  // d_sock is connected and is about to spit out a packet
119
  int len=getLength(timeout);
19,776✔
120
  if(len<0)
19,776!
121
    throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
×
122

123
  if (d_maxReceivedBytes > 0 && (d_maxReceivedBytes - d_receivedBytes) < (size_t) len)
19,776!
124
    throw ResolverException("Reached the maximum number of received bytes during AXFR");
×
125

126
  timeoutReadn(len, timeout);
19,776✔
127

128
  d_receivedBytes += (uint16_t) len;
19,776✔
129

130
  MOADNSParser mdp(false, d_buf.data(), len);
19,776✔
131

132
  int err = mdp.d_header.rcode;
19,776✔
133

134
  if(err) {
19,776!
135
    throw ResolverException("AXFR chunk error: " + RCode::to_s(err));
×
136
  }
×
137

138
  if(mdp.d_header.tc) {
19,776!
139
    throw ResolverException("AXFR chunk had TC bit set");
×
140
  }
×
141

142
  try {
19,776✔
143
    d_tsigVerifier.check(std::string(d_buf.data(), len), mdp);
19,776✔
144
  }
19,776✔
145
  catch(const std::runtime_error& re) {
19,776✔
146
    throw ResolverException(re.what());
×
147
  }
×
148

149
  if(!records) {
19,775✔
150
    err = parseResult(mdp, DNSName(), 0, 0, &res);
19,674✔
151

152
    if (!err) {
19,675✔
153
      for(const auto& answer :  mdp.d_answers) {
1,501,965✔
154
        if (answer.d_type == QType::SOA) {
1,501,965✔
155
          d_soacount++;
896✔
156
        }
896✔
157
      }
1,501,965✔
158
    }
19,675✔
159
  }
19,674✔
160
  else {
101✔
161
    records->clear();
101✔
162
    records->reserve(mdp.d_answers.size());
101✔
163

164
    for(auto& r: mdp.d_answers) {
24,991✔
165
      if (r.d_type == QType::SOA) {
24,991✔
166
        d_soacount++;
32✔
167
      }
32✔
168

169
      records->push_back(std::move(r));
24,991✔
170
    }
24,991✔
171
  }
101✔
172

173
  return true;
19,775✔
174
}
19,776✔
175

176
void AXFRRetriever::timeoutReadn(uint16_t bytes, uint16_t timeoutsec)
177
{
39,552✔
178
  const time_t start = time(nullptr);
39,552✔
179
  uint16_t bytesRead = 0;
39,552✔
180

181
  while (bytesRead < bytes) {
79,112✔
182
    // coverity[store_truncates_time_t]
183
    auto elapsed = time(nullptr) - start;
39,560✔
184
    if (elapsed > timeoutsec) {
39,560!
185
      throw ResolverException("Timeout while reading data from remote nameserver over TCP");
×
186
    }
×
187
    auto res = waitForData(d_sock, static_cast<int>(timeoutsec - elapsed));
39,560✔
188
    if (res < 0) {
39,560!
189
      throw ResolverException("Reading data from remote nameserver over TCP: " + stringerror());
×
190
    }
×
191
    if (res == 0) {
39,560!
192
      throw ResolverException("Timeout while reading data from remote nameserver over TCP");
×
193
    }
×
194

195
    auto received = recv(d_sock, &d_buf.at(bytesRead), bytes - bytesRead, 0);
39,560✔
196
    if (received < 0) {
39,560!
197
      throw ResolverException("Reading data from remote nameserver over TCP: " + stringerror());
×
198
    }
×
199
    if (received == 0) {
39,560!
200
      throw ResolverException("Remote nameserver closed TCP connection");
×
201
    }
×
202
    bytesRead += static_cast<uint16_t>(received);
39,560✔
203
  }
39,560✔
204
}
39,552✔
205

206
void AXFRRetriever::connect(uint16_t timeout)
207
{
467✔
208
  setNonBlocking( d_sock );
467✔
209

210
  int err;
467✔
211

212
  if((err=::connect(d_sock,(struct sockaddr*)&d_remote, d_remote.getSocklen()))<0 && errno!=EINPROGRESS) {
467!
213
    try {
×
214
      closesocket(d_sock);
×
215
    }
×
216
    catch(const PDNSException& e) {
×
217
      d_sock=-1;
×
218
      throw ResolverException("Error closing AXFR socket after connect() failed: "+e.reason);
×
219
    }
×
220

221
    throw ResolverException("connect: "+stringerror());
×
222
  }
×
223

224
  if(!err)
467!
225
    goto done;
×
226

227
  err=waitForRWData(d_sock, false, timeout, 0); // wait for writeability
467✔
228
  
229
  if(!err) {
467!
230
    try {
×
231
      closesocket(d_sock); // timeout
×
232
    }
×
233
    catch(const PDNSException& e) {
×
234
      d_sock=-1;
×
235
      throw ResolverException("Error closing AXFR socket after timeout: "+e.reason);
×
236
    }
×
237

238
    d_sock=-1;
×
239
    errno=ETIMEDOUT;
×
240
    
241
    throw ResolverException("Timeout connecting to server");
×
242
  }
×
243
  else if(err < 0) {
467!
244
    throw ResolverException("Error connecting: "+stringerror());
×
245
  }
×
246
  else {
467✔
247
    Utility::socklen_t len=sizeof(err);
467✔
248
    if(getsockopt(d_sock, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
467!
249
      throw ResolverException("Error connecting: "+stringerror()); // Solaris
×
250

251
    if(err)
467✔
252
      throw ResolverException("Error connecting: "+string(strerror(err)));
3✔
253
  }
467✔
254
  
255
 done:
464✔
256
  setBlocking( d_sock );
464✔
257
  // d_sock now connected
258
}
464✔
259

260
int AXFRRetriever::getLength(uint16_t timeout)
261
{
19,776✔
262
  timeoutReadn(2, timeout);
19,776✔
263
  return (unsigned char)d_buf.at(0)*256+(unsigned char)d_buf.at(1);
19,776✔
264
}
19,776✔
265

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

© 2025 Coveralls, Inc