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

PowerDNS / pdns / 15920880335

26 Jun 2025 03:30PM UTC coverage: 61.923% (-3.7%) from 65.652%
15920880335

push

github

web-flow
Merge pull request #15669 from miodvallat/serial_keyer

Increase zone serial number after zone key operations

38311 of 91850 branches covered (41.71%)

Branch coverage included in aggregate %.

27 of 29 new or added lines in 1 file covered. (93.1%)

6308 existing lines in 78 files now uncovered.

120482 of 164587 relevant lines covered (73.2%)

5965233.22 hits per line

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

55.57
/pdns/iputils.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

26
#include "iputils.hh"
27

28
#include <fstream>
29
#include <sys/socket.h>
30
#include <boost/format.hpp>
31

32
#ifdef HAVE_GETIFADDRS
33
#include <ifaddrs.h>
34
#endif
35

36
/** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */
37

38
static void RuntimeError(const std::string& error)
39
{
×
40
  throw runtime_error(error);
×
41
}
×
42

43
static void NetworkErr(const std::string& error)
44
{
8✔
45
  throw NetworkError(error);
8✔
46
}
8✔
47

48
int SSocket(int family, int type, int flags)
49
{
1,231✔
50
  int ret = socket(family, type, flags);
1,231✔
51
  if (ret < 0) {
1,231!
52
    RuntimeError("creating socket of type " + std::to_string(family) + ": " + stringerror());
×
53
  }
×
54
  return ret;
1,231✔
55
}
1,231✔
56

57
int SConnect(int sockfd, const ComboAddress& remote)
58
{
374✔
59
  int ret = connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
374✔
60
  if (ret < 0) {
374!
61
    int savederrno = errno;
×
62
    RuntimeError("connecting socket to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
×
63
  }
×
64
  return ret;
374✔
65
}
374✔
66

67
int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout)
68
{
19,657✔
69
  int ret = connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
19,657✔
70
  if (ret < 0) {
19,657✔
71
    int savederrno = errno;
3,431✔
72
    if (savederrno == EINPROGRESS) {
3,431✔
73
      if (timeout <= timeval{0, 0}) {
3,427✔
74
        return savederrno;
2,499✔
75
      }
2,499✔
76

77
      /* we wait until the connection has been established */
78
      bool error = false;
928✔
79
      bool disconnected = false;
928✔
80
      int res = waitForRWData(sockfd, false, static_cast<int>(timeout.tv_sec), static_cast<int>(timeout.tv_usec), &error, &disconnected);
928✔
81
      if (res == 1) {
928!
82
        if (error) {
928✔
83
          savederrno = 0;
4✔
84
          socklen_t errlen = sizeof(savederrno);
4✔
85
          if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&savederrno, &errlen) == 0) {
4!
86
            NetworkErr("connecting to " + remote.toStringWithPort() + " failed: " + stringerror(savederrno));
4✔
87
          }
4✔
88
          else {
×
89
            NetworkErr("connecting to " + remote.toStringWithPort() + " failed");
×
90
          }
×
91
        }
4✔
92
        if (disconnected) {
928!
93
          NetworkErr(remote.toStringWithPort() + " closed the connection");
×
94
        }
×
95
        return 0;
928✔
96
      }
928✔
UNCOV
97
      if (res == 0) {
×
98
        NetworkErr("timeout while connecting to " + remote.toStringWithPort());
×
99
      }
×
UNCOV
100
      else if (res < 0) {
×
101
        savederrno = errno;
×
102
        NetworkErr("waiting to connect to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
×
103
      }
×
UNCOV
104
    }
×
105
    else {
4✔
106
      NetworkErr("connecting to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
4✔
107
    }
4✔
108
  }
3,431✔
109

110
  return 0;
16,230✔
111
}
19,657✔
112

113
int SBind(int sockfd, const ComboAddress& local)
114
{
859✔
115
  int ret = bind(sockfd, reinterpret_cast<const struct sockaddr*>(&local), local.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
859✔
116
  if (ret < 0) {
859!
117
    int savederrno = errno;
×
118
    RuntimeError("binding socket to " + local.toStringWithPort() + ": " + stringerror(savederrno));
×
119
  }
×
120
  return ret;
859✔
121
}
859✔
122

123
int SAccept(int sockfd, ComboAddress& remote)
124
{
801✔
125
  socklen_t remlen = remote.getSocklen();
801✔
126

127
  int ret = accept(sockfd, reinterpret_cast<struct sockaddr*>(&remote), &remlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
801✔
128
  if (ret < 0) {
801!
129
    RuntimeError("accepting new connection on socket: " + stringerror());
×
130
  }
×
131
  return ret;
801✔
132
}
801✔
133

134
int SListen(int sockfd, int limit)
135
{
462✔
136
  int ret = listen(sockfd, limit);
462✔
137
  if (ret < 0) {
462!
138
    RuntimeError("setting socket to listen: " + stringerror());
×
139
  }
×
140
  return ret;
462✔
141
}
462✔
142

143
int SSetsockopt(int sockfd, int level, int opname, int value)
144
{
1,582✔
145
  int ret = setsockopt(sockfd, level, opname, &value, sizeof(value));
1,582✔
146
  if (ret < 0) {
1,582!
147
    RuntimeError("setsockopt for level " + std::to_string(level) + " and opname " + std::to_string(opname) + " to " + std::to_string(value) + " failed: " + stringerror());
×
148
  }
×
149
  return ret;
1,582✔
150
}
1,582✔
151

152
void setSocketIgnorePMTU([[maybe_unused]] int sockfd, [[maybe_unused]] int family)
153
{
598✔
154
  if (family == AF_INET) { // NOLINT(bugprone-branch-clone)
598✔
155
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
543✔
156
#ifdef IP_PMTUDISC_OMIT
543✔
157
    /* Linux 3.15+ has IP_PMTUDISC_OMIT, which discards PMTU information to prevent
158
       poisoning, but still allows fragmentation if the packet size exceeds the
159
       outgoing interface MTU, which is good.
160
    */
161
    try {
543✔
162
      SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_OMIT);
543✔
163
      return;
543✔
164
    }
543✔
165
    catch (const std::exception& e) {
543✔
166
      /* failed, let's try IP_PMTUDISC_DONT instead */
167
    }
×
168
#endif /* IP_PMTUDISC_OMIT */
×
169

170
    /* IP_PMTUDISC_DONT disables Path MTU discovery */
171
    SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DONT);
×
172
#endif /* defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) */
×
173
  }
×
174
  else {
55✔
175
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
55✔
176
#ifdef IPV6_PMTUDISC_OMIT
55✔
177
    /* Linux 3.15+ has IPV6_PMTUDISC_OMIT, which discards PMTU information to prevent
178
       poisoning, but still allows fragmentation if the packet size exceeds the
179
       outgoing interface MTU, which is good.
180
    */
181
    try {
55✔
182
      SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, IPV6_PMTUDISC_OMIT);
55✔
183
      return;
55✔
184
    }
55✔
185
    catch (const std::exception& e) {
55✔
186
      /* failed, let's try IP_PMTUDISC_DONT instead */
187
    }
×
188
#endif /* IPV6_PMTUDISC_OMIT */
×
189

190
    /* IPV6_PMTUDISC_DONT disables Path MTU discovery */
191
    SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, IPV6_PMTUDISC_DONT);
×
192
#endif /* defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT) */
×
193
  }
×
194
}
598✔
195

196
void setSocketForcePMTU([[maybe_unused]] int sockfd, [[maybe_unused]] int family)
197
{
31✔
198
  if (family == AF_INET) {
31✔
199
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
29✔
200
    /* IP_PMTUDISC_DO enables Path MTU discovery and prevents fragmentation */
201
    SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DO);
29✔
202
#elif defined(IP_DONTFRAG)
203
    /* at least this prevents fragmentation */
204
    SSetsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, 1);
205
#endif /* defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) */
206
  }
29✔
207
  else {
2✔
208
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
2✔
209
    /* IPV6_PMTUDISC_DO enables Path MTU discovery and prevents fragmentation */
210
    SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, IPV6_PMTUDISC_DO);
2✔
211
#elif defined(IPV6_DONTFRAG)
212
    /* at least this prevents fragmentation */
213
    SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_DONTFRAG, 1);
214
#endif /* defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) */
215
  }
2✔
216
}
31✔
217

218
bool setReusePort(int sockfd)
219
{
14✔
220
#if defined(SO_REUSEPORT_LB)
221
  try {
222
    SSetsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT_LB, 1);
223
    return true;
224
  }
225
  catch (const std::exception& e) {
226
    return false;
227
  }
228
#elif defined(SO_REUSEPORT)
229
  try {
14✔
230
    SSetsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, 1);
14✔
231
    return true;
14✔
232
  }
14✔
233
  catch (const std::exception& e) {
14✔
234
    return false;
×
235
  }
×
236
#endif
×
237
  return false;
×
238
}
14✔
239

240
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval)
241
{
113,593✔
242
  // NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast, cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-type-reinterpret-cast)
243
#ifdef SO_TIMESTAMP
113,593✔
244
  struct cmsghdr* cmsg{};
113,593✔
245
  for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(msgh, cmsg)) {
113,593!
246
    if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP || cmsg->cmsg_type == SCM_TIMESTAMP) && CMSG_LEN(sizeof(*timeval)) == cmsg->cmsg_len) {
113,593!
247
      memcpy(timeval, CMSG_DATA(cmsg), sizeof(*timeval));
113,593✔
248
      return true;
113,593✔
249
    }
113,593✔
250
  }
113,593✔
251
#endif
×
252
  return false;
×
253
}
113,593✔
254
bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination)
255
{
117,183✔
256
  destination->reset();
117,183✔
257
#ifdef __NetBSD__
258
  struct cmsghdr* cmsg{};
259
#else
260
  const struct cmsghdr* cmsg{};
117,183✔
261
#endif
117,183✔
262
  for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(const_cast<struct msghdr*>(msgh), const_cast<struct cmsghdr*>(cmsg))) {
230,776✔
263
#if defined(IP_PKTINFO)
141,191✔
264
    if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
141,191!
265
      const auto* ptr = reinterpret_cast<const struct in_pktinfo*>(CMSG_DATA(cmsg));
27,597✔
266
      destination->sin4.sin_addr = ptr->ipi_addr;
27,597✔
267
      destination->sin4.sin_family = AF_INET;
27,597✔
268
      return true;
27,597✔
269
    }
27,597✔
270
#elif defined(IP_RECVDSTADDR)
271
    if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
272
      const auto* ptr = reinterpret_cast<const struct in_addr*>(CMSG_DATA(cmsg));
273
      destination->sin4.sin_addr = *ptr;
274
      destination->sin4.sin_family = AF_INET;
275
      return true;
276
    }
277
#endif
278

279
    if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_PKTINFO)) {
113,594!
280
      const auto* ptr = reinterpret_cast<const struct in6_pktinfo*>(CMSG_DATA(cmsg));
1✔
281
      destination->sin6.sin6_addr = ptr->ipi6_addr;
1✔
282
      destination->sin4.sin_family = AF_INET6;
1✔
283
      return true;
1✔
284
    }
1✔
285
  }
113,594✔
286
  return false;
89,585✔
287
  // NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast, cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-type-reinterpret-cast)
288
}
117,183✔
289

290
bool IsAnyAddress(const ComboAddress& addr)
291
{
7,454✔
292
  if (addr.sin4.sin_family == AF_INET) {
7,454✔
293
    return addr.sin4.sin_addr.s_addr == 0;
7,391✔
294
  }
7,391✔
295
  if (addr.sin4.sin_family == AF_INET6) {
63!
296
    return memcmp(&addr.sin6.sin6_addr, &in6addr_any, sizeof(addr.sin6.sin6_addr)) == 0;
63✔
297
  }
63✔
298
  return false;
×
299
}
63✔
300

301
int sendOnNBSocket(int fileDesc, const struct msghdr* msgh)
302
{
113,249✔
303
  int sendErr = 0;
113,249✔
304
#ifdef __OpenBSD__
305
  // OpenBSD can and does return EAGAIN on non-blocking datagram sockets
306
  for (int i = 0; i < 10; i++) { // Arbitrary upper bound
307
    if (sendmsg(fileDesc, msgh, 0) != -1) {
308
      sendErr = 0;
309
      break;
310
    }
311
    sendErr = errno;
312
    if (sendErr != EAGAIN) {
313
      break;
314
    }
315
  }
316
#else
317
  if (sendmsg(fileDesc, msgh, 0) == -1) {
113,249!
318
    sendErr = errno;
×
319
  }
×
320
#endif
113,249✔
321
  return sendErr;
113,249✔
322
}
113,249✔
323

324
// be careful: when using this for receive purposes, make sure addr->sin4.sin_family is set appropriately so getSocklen works!
325
// be careful: when using this function for *send* purposes, be sure to set cbufsize to 0!
326
// be careful: if you don't call addCMsgSrcAddr after fillMSGHdr, make sure to set msg_control to NULL
327
void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr)
328
{
229,094✔
329
  iov->iov_base = data;
229,094✔
330
  iov->iov_len = datalen;
229,094✔
331

332
  memset(msgh, 0, sizeof(struct msghdr));
229,094✔
333

334
  msgh->msg_control = cbuf;
229,094✔
335
  msgh->msg_controllen = cbufsize;
229,094✔
336
  msgh->msg_name = addr;
229,094✔
337
  msgh->msg_namelen = addr->getSocklen();
229,094✔
338
  msgh->msg_iov = iov;
229,094✔
339
  msgh->msg_iovlen = 1;
229,094✔
340
  msgh->msg_flags = 0;
229,094✔
341
}
229,094✔
342

343
// warning: various parts of PowerDNS assume 'truncate' will never throw
344
void ComboAddress::truncate(unsigned int bits) noexcept
345
{
133,167✔
346
  uint8_t* start{};
133,167✔
347
  int len = 4;
133,167✔
348
  if (sin4.sin_family == AF_INET) {
133,167✔
349
    if (bits >= 32) {
132,433✔
350
      return;
131,705✔
351
    }
131,705✔
352
    start = reinterpret_cast<uint8_t*>(&sin4.sin_addr.s_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
728✔
353
    len = 4;
728✔
354
  }
728✔
355
  else {
734✔
356
    if (bits >= 128) {
734✔
357
      return;
21✔
358
    }
21✔
359
    start = reinterpret_cast<uint8_t*>(&sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
713✔
360
    len = 16;
713✔
361
  }
713✔
362

363
  auto tozero = len * 8 - bits; // if set to 22, this will clear 1 byte, as it should
1,441✔
364

365
  memset(start + len - tozero / 8, 0, tozero / 8); // blot out the whole bytes on the right NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1,441✔
366

367
  auto bitsleft = tozero % 8; // 2 bits left to clear
1,441✔
368

369
  // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c
370
  // so and by '11111100', which is ~((1<<2)-1)  = ~3
371
  uint8_t* place = start + len - 1 - tozero / 8; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1,441✔
372
  *place &= (~((1 << bitsleft) - 1));
1,441✔
373
}
1,441✔
374

375
size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags)
376
{
830✔
377
  msghdr msgh{};
830✔
378
  iovec iov{};
830✔
379
  cmsgbuf_aligned cbuf;
830✔
380

381
  /* Set up iov and msgh structures. */
382
  memset(&msgh, 0, sizeof(msgh));
830✔
383
  msgh.msg_control = nullptr;
830✔
384
  msgh.msg_controllen = 0;
830✔
385
  if (dest != nullptr) {
830!
386
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-type-const-cast): it's the API
387
    msgh.msg_name = reinterpret_cast<void*>(const_cast<ComboAddress*>(dest));
830✔
388
    msgh.msg_namelen = dest->getSocklen();
830✔
389
  }
830✔
390
  else {
×
391
    msgh.msg_name = nullptr;
×
392
    msgh.msg_namelen = 0;
×
393
  }
×
394

395
  msgh.msg_flags = 0;
830✔
396

397
  if (local != nullptr && local->sin4.sin_family != 0) {
830!
398
    addCMsgSrcAddr(&msgh, &cbuf, local, static_cast<int>(localItf));
830✔
399
  }
830✔
400

401
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): it's the API
402
  iov.iov_base = const_cast<void*>(buffer);
830✔
403
  iov.iov_len = len;
830✔
404
  msgh.msg_iov = &iov;
830✔
405
  msgh.msg_iovlen = 1;
830✔
406
  msgh.msg_flags = 0;
830✔
407

408
  size_t sent = 0;
830✔
409
#ifdef MSG_FASTOPEN
830✔
410
  bool firstTry = true;
830✔
411
#endif
830✔
412

413
  do {
830✔
414

415
#ifdef MSG_FASTOPEN
830✔
416
    if ((flags & MSG_FASTOPEN) != 0 && !firstTry) {
830!
417
      flags &= ~MSG_FASTOPEN;
×
418
    }
×
419
#endif /* MSG_FASTOPEN */
830✔
420

421
    ssize_t res = sendmsg(socketDesc, &msgh, flags);
830✔
422

423
    if (res > 0) {
830!
424
      auto written = static_cast<size_t>(res);
830✔
425
      sent += written;
830✔
426

427
      if (sent == len) {
830!
428
        return sent;
830✔
429
      }
830✔
430

431
      /* partial write */
432
#ifdef MSG_FASTOPEN
×
433
      firstTry = false;
×
434
#endif
×
435
      iov.iov_len -= written;
×
436
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic): it's the API
437
      iov.iov_base = reinterpret_cast<void*>(reinterpret_cast<char*>(iov.iov_base) + written);
×
438
    }
×
439
    else if (res == 0) {
×
440
      return res;
×
441
    }
×
442
    else if (res == -1) {
×
443
      int err = errno;
×
444
      if (err == EINTR) {
×
445
        continue;
×
446
      }
×
447
      if (err == EAGAIN || err == EWOULDBLOCK || err == EINPROGRESS || err == ENOTCONN) {
×
448
        /* EINPROGRESS might happen with non blocking socket,
449
           especially with TCP Fast Open */
450
        return sent;
×
451
      }
×
452
      unixDie("failed in sendMsgWithOptions");
×
453
    }
×
454
  } while (true);
830✔
455

456
  return 0;
×
457
}
830✔
458

459
template class NetmaskTree<bool, Netmask>;
460

461
/* requires a non-blocking socket.
462
   On Linux, we could use MSG_DONTWAIT on a blocking socket
463
   but this is not portable.
464
*/
465
bool isTCPSocketUsable(int sock)
466
{
111,160✔
467
  int err = 0;
111,160✔
468
  char buf = '\0';
111,160✔
469
  size_t buf_size = sizeof(buf);
111,160✔
470

471
  do {
111,160✔
472
    ssize_t got = recv(sock, &buf, buf_size, MSG_PEEK);
111,160✔
473

474
    if (got > 0) {
111,160!
475
      /* socket is usable, some data is even waiting to be read */
476
      return true;
×
477
    }
×
478
    if (got == 0) {
111,160✔
479
      /* other end has closed the socket */
480
      return false;
92✔
481
    }
92✔
482
    err = errno;
111,068✔
483
    if (err == EAGAIN || err == EWOULDBLOCK) {
111,068!
484
      /* socket is usable, no data waiting */
485
      return true;
111,067✔
486
    }
111,067✔
487
    if (err != EINTR) {
1!
488
      /* something is wrong, could be ECONNRESET,
489
         ENOTCONN, EPIPE, but anyway this socket is
490
         not usable. */
491
      return false;
×
492
    }
×
493
  } while (err == EINTR);
1!
494

495
  return false;
1✔
496
}
111,160✔
497
/* mission in life: parse four cases
498
   1) [2002::1]:53
499
   2) 1.2.3.4
500
   3) 1.2.3.4:5300
501
   4) 2001::1 no port allowed
502
*/
503

504
ComboAddress parseIPAndPort(const std::string& input, uint16_t port)
505
{
60✔
506
  if (input[0] == '[') { // case 1
60✔
507
    auto both = splitField(input.substr(1), ']');
10✔
508
    return ComboAddress(both.first, both.second.empty() ? port : pdns::checked_stoi<uint16_t>(both.second.substr(1)));
10!
509
  }
10✔
510

511
  string::size_type count = 0;
50✔
512
  for (char chr : input) {
275✔
513
    if (chr == ':') {
275✔
514
      count++;
60✔
515
    }
60✔
516
    if (count > 1) {
275✔
517
      break;
30✔
518
    }
30✔
519
  }
275✔
520
  switch (count) {
50✔
521
  case 0: // case 2
20✔
522
    return ComboAddress(input, port);
20✔
UNCOV
523
  case 1: { // case 3
×
UNCOV
524
    string::size_type cpos = input.rfind(':');
×
UNCOV
525
    pair<std::string, std::string> both;
×
UNCOV
526
    both.first = input.substr(0, cpos);
×
UNCOV
527
    both.second = input.substr(cpos + 1);
×
528

UNCOV
529
    auto newport = pdns::checked_stoi<uint16_t>(both.second);
×
UNCOV
530
    return ComboAddress(both.first, newport);
×
531
  }
×
532
  default: // case 4
30✔
533
    return ComboAddress(input, port);
30✔
534
  }
50✔
535
}
50✔
536

537
void setSocketBuffer(int fileDesc, int optname, uint32_t size)
538
{
816✔
539
  uint32_t psize = 0;
816✔
540
  socklen_t len = sizeof(psize);
816✔
541

542
  if (getsockopt(fileDesc, SOL_SOCKET, optname, &psize, &len) != 0) {
816!
543
    throw std::runtime_error("Unable to retrieve socket buffer size:" + stringerror());
×
544
  }
×
545
  if (psize >= size) {
816✔
546
    return;
801✔
547
  }
801✔
548
  if (setsockopt(fileDesc, SOL_SOCKET, optname, &size, sizeof(size)) != 0) {
15!
549
    throw std::runtime_error("Unable to raise socket buffer size to " + std::to_string(size) + ": " + stringerror());
×
550
  }
×
551
}
15✔
552

553
void setSocketReceiveBuffer(int fileDesc, uint32_t size)
554
{
15✔
555
  setSocketBuffer(fileDesc, SO_RCVBUF, size);
15✔
556
}
15✔
557

558
void setSocketSendBuffer(int fileDesc, uint32_t size)
559
{
15✔
560
  setSocketBuffer(fileDesc, SO_SNDBUF, size);
15✔
561
}
15✔
562

563
#ifdef __linux__
564
static uint32_t raiseSocketBufferToMax(int socket, int optname, const std::string& readMaxFromFile)
565
{
786✔
566
  std::ifstream ifs(readMaxFromFile);
786✔
567
  if (ifs) {
786!
568
    std::string line;
786✔
569
    if (getline(ifs, line)) {
786!
570
      auto max = pdns::checked_stoi<uint32_t>(line);
786✔
571
      setSocketBuffer(socket, optname, max);
786✔
572
      return max;
786✔
573
    }
786✔
574
  }
786✔
575
  return 0;
×
576
}
786✔
577
#endif
578

579
uint32_t raiseSocketReceiveBufferToMax([[maybe_unused]] int socket)
580
{
393✔
581
#ifdef __linux__
393✔
582
  return raiseSocketBufferToMax(socket, SO_RCVBUF, "/proc/sys/net/core/rmem_max");
393✔
583
#else
584
  return 0;
585
#endif
586
}
393✔
587

588
uint32_t raiseSocketSendBufferToMax([[maybe_unused]] int socket)
589
{
393✔
590
#ifdef __linux__
393✔
591
  return raiseSocketBufferToMax(socket, SO_SNDBUF, "/proc/sys/net/core/wmem_max");
393✔
592
#else
593
  return 0;
594
#endif
595
}
393✔
596

597
std::set<std::string> getListOfNetworkInterfaces()
598
{
×
599
  std::set<std::string> result;
×
600
#ifdef HAVE_GETIFADDRS
×
601
  struct ifaddrs* ifaddr{};
×
602
  if (getifaddrs(&ifaddr) == -1) {
×
603
    return result;
×
604
  }
×
605

606
  for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
×
607
    if (ifa->ifa_name == nullptr) {
×
608
      continue;
×
609
    }
×
610
    result.insert(ifa->ifa_name);
×
611
  }
×
612

613
  freeifaddrs(ifaddr);
×
614
#endif
×
615
  return result;
×
616
}
×
617

618
#ifdef HAVE_GETIFADDRS
619
std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf)
620
{
×
621
  std::vector<ComboAddress> result;
×
622
  struct ifaddrs* ifaddr = nullptr;
×
623
  if (getifaddrs(&ifaddr) == -1) {
×
624
    return result;
×
625
  }
×
626

627
  for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
×
628
    if (ifa->ifa_name == nullptr || strcmp(ifa->ifa_name, itf.c_str()) != 0) {
×
629
      continue;
×
630
    }
×
631
    if (ifa->ifa_addr == nullptr || (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)) {
×
632
      continue;
×
633
    }
×
634
    ComboAddress addr;
×
635
    try {
×
636
      addr.setSockaddr(ifa->ifa_addr, ifa->ifa_addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
×
637
    }
×
638
    catch (...) {
×
639
      continue;
×
640
    }
×
641

642
    result.push_back(addr);
×
643
  }
×
644

645
  freeifaddrs(ifaddr);
×
646
  return result;
×
647
}
×
648
#else
649
std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& /* itf */)
650
{
651
  std::vector<ComboAddress> result;
652
  return result;
653
}
654
#endif // HAVE_GETIFADDRS
655

656
#ifdef HAVE_GETIFADDRS
657
static uint8_t convertNetmaskToBits(const uint8_t* mask, socklen_t len)
658
{
×
659
  if (mask == nullptr || len > 16) {
×
660
    throw std::runtime_error("Invalid parameters passed to convertNetmaskToBits");
×
661
  }
×
662

663
  uint8_t result = 0;
×
664
  // for all bytes in the address (4 for IPv4, 16 for IPv6)
665
  for (size_t idx = 0; idx < len; idx++) {
×
666
    uint8_t byte = *(mask + idx); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
×
667
    // count the number of bits set
668
    while (byte > 0) {
×
669
      result += (byte & 1);
×
670
      byte >>= 1;
×
671
    }
×
672
  }
×
673
  return result;
×
674
}
×
675
#endif /* HAVE_GETIFADDRS */
676

677
#ifdef HAVE_GETIFADDRS
678
std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf)
679
{
×
680
  std::vector<Netmask> result;
×
681
  struct ifaddrs* ifaddr = nullptr;
×
682
  if (getifaddrs(&ifaddr) == -1) {
×
683
    return result;
×
684
  }
×
685

686
  for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
×
687
    if (ifa->ifa_name == nullptr || strcmp(ifa->ifa_name, itf.c_str()) != 0) {
×
688
      continue;
×
689
    }
×
690
    if (ifa->ifa_addr == nullptr || (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)) {
×
691
      continue;
×
692
    }
×
693
    ComboAddress addr;
×
694
    try {
×
695
      addr.setSockaddr(ifa->ifa_addr, ifa->ifa_addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
×
696
    }
×
697
    catch (...) {
×
698
      continue;
×
699
    }
×
700

701
    // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
702
    if (ifa->ifa_addr->sa_family == AF_INET) {
×
703
      const auto* netmask = reinterpret_cast<const struct sockaddr_in*>(ifa->ifa_netmask);
×
704
      uint8_t maskBits = convertNetmaskToBits(reinterpret_cast<const uint8_t*>(&netmask->sin_addr.s_addr), sizeof(netmask->sin_addr.s_addr));
×
705
      result.emplace_back(addr, maskBits);
×
706
    }
×
707
    else if (ifa->ifa_addr->sa_family == AF_INET6) {
×
708
      const auto* netmask = reinterpret_cast<const struct sockaddr_in6*>(ifa->ifa_netmask);
×
709
      uint8_t maskBits = convertNetmaskToBits(reinterpret_cast<const uint8_t*>(&netmask->sin6_addr.s6_addr), sizeof(netmask->sin6_addr.s6_addr));
×
710
      result.emplace_back(addr, maskBits);
×
711
    }
×
712
    // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
713
  }
×
714

715
  freeifaddrs(ifaddr);
×
716
  return result;
×
717
}
×
718
#else
719
std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& /* itf */)
720
{
721
  std::vector<Netmask> result;
722
  return result;
723
}
724
#endif // HAVE_GETIFADDRS
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