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

PowerDNS / pdns / 18225652081

03 Oct 2025 02:49PM UTC coverage: 65.825%. Remained the same
18225652081

Pull #16211

github

web-flow
Merge a109c2507 into feeb24672
Pull Request #16211: auth 5.0.x: backport "grow auth source tarballs fatter"

42048 of 92452 branches covered (45.48%)

Branch coverage included in aggregate %.

127983 of 165855 relevant lines covered (77.17%)

5370244.34 hits per line

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

56.03
/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
{
38✔
45
  throw NetworkError(error);
38✔
46
}
38✔
47

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

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

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

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

110
  return 0;
18,288✔
111
}
22,067✔
112

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

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

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

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

143
int SSetsockopt(int sockfd, int level, int opname, int value)
144
{
2,458✔
145
  int ret = setsockopt(sockfd, level, opname, &value, sizeof(value));
2,458✔
146
  if (ret < 0) {
2,458!
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;
2,458✔
150
}
2,458✔
151

152
void setSocketIgnorePMTU([[maybe_unused]] int sockfd, [[maybe_unused]] int family)
153
{
948✔
154
  if (family == AF_INET) { // NOLINT(bugprone-branch-clone)
948✔
155
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
874✔
156
#ifdef IP_PMTUDISC_OMIT
874✔
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 {
874✔
162
      SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_OMIT);
874✔
163
      return;
874✔
164
    }
874✔
165
    catch (const std::exception& e) {
874✔
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 {
74✔
175
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
74✔
176
#ifdef IPV6_PMTUDISC_OMIT
74✔
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 {
74✔
182
      SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, IPV6_PMTUDISC_OMIT);
74✔
183
      return;
74✔
184
    }
74✔
185
    catch (const std::exception& e) {
74✔
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
}
948✔
195

196
void setSocketForcePMTU([[maybe_unused]] int sockfd, [[maybe_unused]] int family)
197
{
35✔
198
  if (family == AF_INET) {
35✔
199
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
33✔
200
    /* IP_PMTUDISC_DO enables Path MTU discovery and prevents fragmentation */
201
    SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DO);
33✔
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
  }
33✔
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
}
35✔
217

218
bool setReusePort(int sockfd)
219
{
18✔
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 {
18✔
230
    SSetsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, 1);
18✔
231
    return true;
18✔
232
  }
18✔
233
  catch (const std::exception& e) {
18✔
234
    return false;
×
235
  }
×
236
#endif
×
237
  return false;
×
238
}
18✔
239

240
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval)
241
{
131,857✔
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
131,857✔
244
  struct cmsghdr* cmsg{};
131,857✔
245
  for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(msgh, cmsg)) {
131,857!
246
    if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP || cmsg->cmsg_type == SCM_TIMESTAMP) && CMSG_LEN(sizeof(*timeval)) == cmsg->cmsg_len) {
131,857!
247
      memcpy(timeval, CMSG_DATA(cmsg), sizeof(*timeval));
131,857✔
248
      return true;
131,857✔
249
    }
131,857✔
250
  }
131,857✔
251
#endif
×
252
  return false;
×
253
}
131,857✔
254
bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination)
255
{
135,611✔
256
  destination->reset();
135,611✔
257
#ifdef __NetBSD__
258
  struct cmsghdr* cmsg{};
259
#else
260
  const struct cmsghdr* cmsg{};
135,611✔
261
#endif
135,611✔
262
  for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(const_cast<struct msghdr*>(msgh), const_cast<struct cmsghdr*>(cmsg))) {
267,481✔
263
#if defined(IP_PKTINFO)
159,434✔
264
    if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
159,434!
265
      const auto* ptr = reinterpret_cast<const struct in_pktinfo*>(CMSG_DATA(cmsg));
27,563✔
266
      destination->sin4.sin_addr = ptr->ipi_addr;
27,563✔
267
      destination->sin4.sin_family = AF_INET;
27,563✔
268
      return true;
27,563✔
269
    }
27,563✔
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)) {
131,871!
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
  }
131,871✔
286
  return false;
108,047✔
287
  // NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast, cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-type-reinterpret-cast)
288
}
135,611✔
289

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

301
int sendOnNBSocket(int fileDesc, const struct msghdr* msgh)
302
{
131,544✔
303
  int sendErr = 0;
131,544✔
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) {
131,544!
318
    sendErr = errno;
×
319
  }
×
320
#endif
131,544✔
321
  return sendErr;
131,544✔
322
}
131,544✔
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
{
266,568✔
329
  iov->iov_base = data;
266,568✔
330
  iov->iov_len = datalen;
266,568✔
331

332
  memset(msgh, 0, sizeof(struct msghdr));
266,568✔
333

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

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

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

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

367
  auto bitsleft = tozero % 8; // 2 bits left to clear
3,405✔
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)
3,405✔
372
  *place &= (~((1 << bitsleft) - 1));
3,405✔
373
}
3,405✔
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
{
858✔
377
  msghdr msgh{};
858✔
378
  iovec iov{};
858✔
379
  cmsgbuf_aligned cbuf;
858✔
380

381
  /* Set up iov and msgh structures. */
382
  memset(&msgh, 0, sizeof(msgh));
858✔
383
  msgh.msg_control = nullptr;
858✔
384
  msgh.msg_controllen = 0;
858✔
385
  if (dest != nullptr) {
858!
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));
858✔
388
    msgh.msg_namelen = dest->getSocklen();
858✔
389
  }
858✔
390
  else {
×
391
    msgh.msg_name = nullptr;
×
392
    msgh.msg_namelen = 0;
×
393
  }
×
394

395
  msgh.msg_flags = 0;
858✔
396

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

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

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

413
  do {
858✔
414

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

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

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

427
      if (sent == len) {
858!
428
        return sent;
858✔
429
      }
858✔
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);
858✔
455

456
  return 0;
×
457
}
858✔
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,475✔
467
  int err = 0;
111,475✔
468
  char buf = '\0';
111,475✔
469
  size_t buf_size = sizeof(buf);
111,475✔
470

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

474
    if (got > 0) {
111,475!
475
      /* socket is usable, some data is even waiting to be read */
476
      return true;
×
477
    }
×
478
    if (got == 0) {
111,475✔
479
      /* other end has closed the socket */
480
      return false;
93✔
481
    }
93✔
482
    err = errno;
111,382✔
483
    if (err == EAGAIN || err == EWOULDBLOCK) {
111,382!
484
      /* socket is usable, no data waiting */
485
      return true;
111,382✔
486
    }
111,382✔
487
    if (err != EINTR) {
×
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);
×
494

495
  return false;
×
496
}
111,475✔
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
{
2,918✔
506
  if (input[0] == '[') { // case 1
2,918✔
507
    auto both = splitField(input.substr(1), ']');
12✔
508
    return ComboAddress(both.first, both.second.empty() ? port : pdns::checked_stoi<uint16_t>(both.second.substr(1)));
12!
509
  }
12✔
510

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

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

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

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

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

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

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

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

588
uint32_t raiseSocketSendBufferToMax([[maybe_unused]] int socket)
589
{
410✔
590
#ifdef __linux__
410✔
591
  return raiseSocketBufferToMax(socket, SO_SNDBUF, "/proc/sys/net/core/wmem_max");
410✔
592
#else
593
  return 0;
594
#endif
595
}
410✔
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