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

PowerDNS / pdns / 10789862120

10 Sep 2024 09:38AM UTC coverage: 55.763% (-0.03%) from 55.792%
10789862120

push

github

web-flow
Merge pull request #14641 from rgacogne/ddist19-backport-14573

dnsdist-1.9.x: Backport 14573 - Stop reporting timeouts in `topSlow()`, add `topTimeouts()`

13812 of 45324 branches covered (30.47%)

Branch coverage included in aggregate %.

3 of 9 new or added lines in 1 file covered. (33.33%)

13 existing lines in 4 files now uncovered.

47994 of 65513 relevant lines covered (73.26%)

3755251.71 hits per line

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

47.55
/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
{
2✔
40
  throw runtime_error(error);
2✔
41
}
2✔
42

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

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

57
int SConnect(int sockfd, const ComboAddress& remote)
58
{
320✔
59
  int ret = connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen());
320✔
60
  if (ret < 0) {
320✔
61
    int savederrno = errno;
2✔
62
    RuntimeError("connecting socket to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
2✔
63
  }
2✔
64
  return ret;
320✔
65
}
320✔
66

67
int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout)
68
{
2,910✔
69
  int ret = connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen());
2,910✔
70
  if(ret < 0) {
2,910✔
71
    int savederrno = errno;
1,819✔
72
    if (savederrno == EINPROGRESS) {
1,819✔
73
      if (timeout <= timeval{0,0}) {
1,807✔
74
        return savederrno;
1,774✔
75
      }
1,774✔
76

77
      /* we wait until the connection has been established */
78
      bool error = false;
33✔
79
      bool disconnected = false;
33✔
80
      int res = waitForRWData(sockfd, false, timeout.tv_sec, timeout.tv_usec, &error, &disconnected);
33✔
81
      if (res == 1) {
33!
82
        if (error) {
33✔
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) {
33!
93
          NetworkErr(remote.toStringWithPort() + " closed the connection");
×
94
        }
×
95
        return 0;
33✔
96
      }
33✔
UNCOV
97
      else if (res == 0) {
×
98
        NetworkErr("timeout while connecting to " + remote.toStringWithPort());
×
UNCOV
99
      } else if (res < 0) {
×
100
        savederrno = errno;
×
101
        NetworkErr("waiting to connect to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
×
102
      }
×
103
    }
33✔
104
    else {
12✔
105
      NetworkErr("connecting to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
12✔
106
    }
12✔
107
  }
1,819✔
108

109
  return 0;
1,103✔
110
}
2,910✔
111

112
int SBind(int sockfd, const ComboAddress& local)
113
{
753✔
114
  int ret = bind(sockfd, (struct sockaddr*)&local, local.getSocklen());
753✔
115
  if (ret < 0) {
753!
116
    int savederrno = errno;
×
117
    RuntimeError("binding socket to " + local.toStringWithPort() + ": " + stringerror(savederrno));
×
118
  }
×
119
  return ret;
753✔
120
}
753✔
121

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

126
  int ret = accept(sockfd, (struct sockaddr*)&remote, &remlen);
657✔
127
  if (ret < 0) {
657!
128
    RuntimeError("accepting new connection on socket: " + stringerror());
×
129
  }
×
130
  return ret;
657✔
131
}
657✔
132

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

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

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

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

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

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

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

239
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv)
240
{
×
241
#ifdef SO_TIMESTAMP
×
242
  struct cmsghdr *cmsg;
×
243
  for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(msgh,cmsg)) {
×
244
    if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP || cmsg->cmsg_type == SCM_TIMESTAMP) &&
×
245
        CMSG_LEN(sizeof(*tv)) == cmsg->cmsg_len) {
×
246
      memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv));
×
247
      return true;
×
248
    }
×
249
  }
×
250
#endif
×
251
  return false;
×
252
}
×
253
bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination)
254
{
2,415✔
255
  destination->reset();
2,415✔
256
#ifdef __NetBSD__
257
  struct cmsghdr* cmsg;
258
#else
259
  const struct cmsghdr* cmsg;
2,415✔
260
#endif
2,415✔
261
  for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(const_cast<struct msghdr*>(msgh), const_cast<struct cmsghdr*>(cmsg))) {
2,415✔
262
#if defined(IP_PKTINFO)
19✔
263
     if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
19!
264
        struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
18✔
265
        destination->sin4.sin_addr = i->ipi_addr;
18✔
266
        destination->sin4.sin_family = AF_INET;
18✔
267
        return true;
18✔
268
    }
18✔
269
#elif defined(IP_RECVDSTADDR)
270
    if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
271
      struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
272
      destination->sin4.sin_addr = *i;
273
      destination->sin4.sin_family = AF_INET;
274
      return true;
275
    }
276
#endif
277

278
    if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_PKTINFO)) {
1!
279
        struct in6_pktinfo *i = (struct in6_pktinfo *) CMSG_DATA(cmsg);
1✔
280
        destination->sin6.sin6_addr = i->ipi6_addr;
1✔
281
        destination->sin4.sin_family = AF_INET6;
1✔
282
        return true;
1✔
283
    }
1✔
284
  }
1✔
285
  return false;
2,396✔
286
}
2,415✔
287

288
bool IsAnyAddress(const ComboAddress& addr)
289
{
5,346✔
290
  if(addr.sin4.sin_family == AF_INET)
5,346✔
291
    return addr.sin4.sin_addr.s_addr == 0;
5,337✔
292
  else if(addr.sin4.sin_family == AF_INET6)
9!
293
    return !memcmp(&addr.sin6.sin6_addr, &in6addr_any, sizeof(addr.sin6.sin6_addr));
9✔
294

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

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

328
  memset(msgh, 0, sizeof(struct msghdr));
1,387✔
329

330
  msgh->msg_control = cbuf;
1,387✔
331
  msgh->msg_controllen = cbufsize;
1,387✔
332
  msgh->msg_name = addr;
1,387✔
333
  msgh->msg_namelen = addr->getSocklen();
1,387✔
334
  msgh->msg_iov  = iov;
1,387✔
335
  msgh->msg_iovlen = 1;
1,387✔
336
  msgh->msg_flags = 0;
1,387✔
337
}
1,387✔
338

339
// warning: various parts of PowerDNS assume 'truncate' will never throw
340
void ComboAddress::truncate(unsigned int bits) noexcept
341
{
131,775✔
342
  uint8_t* start;
131,775✔
343
  int len=4;
131,775✔
344
  if(sin4.sin_family==AF_INET) {
131,775✔
345
    if(bits >= 32)
131,491✔
346
      return;
131,166✔
347
    start = (uint8_t*)&sin4.sin_addr.s_addr;
325✔
348
    len=4;
325✔
349
  }
325✔
350
  else {
284✔
351
    if(bits >= 128)
284✔
352
      return;
2✔
353
    start = (uint8_t*)&sin6.sin6_addr.s6_addr;
282✔
354
    len=16;
282✔
355
  }
282✔
356

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

359
  memset(start + len - tozero/8, 0, tozero/8); // blot out the whole bytes on the right
607✔
360

361
  auto bitsleft=tozero % 8; // 2 bits left to clear
607✔
362

363
  // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c
364
  // so and by '11111100', which is ~((1<<2)-1)  = ~3
365
  uint8_t* place = start + len - 1 - tozero/8;
607✔
366
  *place &= (~((1<<bitsleft)-1));
607✔
367
}
607✔
368

369
size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags)
370
{
517✔
371
  msghdr msgh{};
517✔
372
  iovec iov{};
517✔
373
  cmsgbuf_aligned cbuf;
517✔
374

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

389
  msgh.msg_flags = 0;
517✔
390

391
  if (local != nullptr && local->sin4.sin_family != 0) {
517!
392
    addCMsgSrcAddr(&msgh, &cbuf, local, static_cast<int>(localItf));
517✔
393
  }
517✔
394

395
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): it's the API
396
  iov.iov_base = const_cast<void*>(buffer);
517✔
397
  iov.iov_len = len;
517✔
398
  msgh.msg_iov = &iov;
517✔
399
  msgh.msg_iovlen = 1;
517✔
400
  msgh.msg_flags = 0;
517✔
401

402
  size_t sent = 0;
517✔
403
#ifdef MSG_FASTOPEN
517✔
404
  bool firstTry = true;
517✔
405
#endif
517✔
406

407
  do {
517✔
408

409
#ifdef MSG_FASTOPEN
517✔
410
    if ((flags & MSG_FASTOPEN) != 0 && !firstTry) {
517!
411
      flags &= ~MSG_FASTOPEN;
×
412
    }
×
413
#endif /* MSG_FASTOPEN */
517✔
414

415
    ssize_t res = sendmsg(socketDesc, &msgh, flags);
517✔
416

417
    if (res > 0) {
517!
418
      auto written = static_cast<size_t>(res);
517✔
419
      sent += written;
517✔
420

421
      if (sent == len) {
517!
422
        return sent;
517✔
423
      }
517✔
424

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

451
  return 0;
×
452
}
517✔
453

454
template class NetmaskTree<bool, Netmask>;
455

456
/* requires a non-blocking socket.
457
   On Linux, we could use MSG_DONTWAIT on a blocking socket
458
   but this is not portable.
459
*/
460
bool isTCPSocketUsable(int sock)
461
{
94✔
462
  int err = 0;
94✔
463
  char buf = '\0';
94✔
464
  size_t buf_size = sizeof(buf);
94✔
465

466
  do {
94✔
467
    ssize_t got = recv(sock, &buf, buf_size, MSG_PEEK);
94✔
468

469
    if (got > 0) {
94!
470
      /* socket is usable, some data is even waiting to be read */
471
      return true;
×
472
    }
×
473
    else if (got == 0) {
94✔
474
      /* other end has closed the socket */
475
      return false;
92✔
476
    }
92✔
477
    else {
2✔
478
      err = errno;
2✔
479

480
      if (err == EAGAIN || err == EWOULDBLOCK) {
2!
481
        /* socket is usable, no data waiting */
482
        return true;
2✔
483
      }
2✔
484
      else {
×
485
        if (err != EINTR) {
×
486
          /* something is wrong, could be ECONNRESET,
487
             ENOTCONN, EPIPE, but anyway this socket is
488
             not usable. */
489
          return false;
×
490
        }
×
491
      }
×
492
    }
2✔
493
  } while (err == EINTR);
94!
494

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

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

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

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

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

553
void setSocketReceiveBuffer(int fd, uint32_t size)
554
{
×
555
  setSocketBuffer(fd, SO_RCVBUF, size);
×
556
}
×
557

558
void setSocketSendBuffer(int fd, uint32_t size)
559
{
×
560
  setSocketBuffer(fd, SO_SNDBUF, size);
×
561
}
×
562

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

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

588
uint32_t raiseSocketSendBufferToMax([[maybe_unused]] int socket)
589
{
328✔
590
#ifdef __linux__
328✔
591
  return raiseSocketBufferToMax(socket, SO_SNDBUF, "/proc/sys/net/core/wmem_max");
328✔
592
#else
593
  return 0;
594
#endif
595
}
328✔
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);
×
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
    if (ifa->ifa_addr->sa_family == AF_INET) {
×
702
      auto netmask = reinterpret_cast<const struct sockaddr_in*>(ifa->ifa_netmask);
×
703
      uint8_t maskBits = convertNetmaskToBits(reinterpret_cast<const uint8_t*>(&netmask->sin_addr.s_addr), sizeof(netmask->sin_addr.s_addr));
×
704
      result.emplace_back(addr, maskBits);
×
705
    }
×
706
    else if (ifa->ifa_addr->sa_family == AF_INET6) {
×
707
      auto netmask = reinterpret_cast<const struct sockaddr_in6*>(ifa->ifa_netmask);
×
708
      uint8_t maskBits = convertNetmaskToBits(reinterpret_cast<const uint8_t*>(&netmask->sin6_addr.s6_addr), sizeof(netmask->sin6_addr.s6_addr));
×
709
      result.emplace_back(addr, maskBits);
×
710
    }
×
711
  }
×
712

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