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

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

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

91.94
/pdns/dnsdistdist/dnsdist-lua-network.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
#include <sys/socket.h>
23
#include <sys/un.h>
24

25
#include "dnsdist-lua-network.hh"
26
#include "dolog.hh"
27
#include "threadname.hh"
28

29
namespace dnsdist
30
{
31
NetworkListener::ListenerData::ListenerData() :
32
  d_mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(10)))
29✔
33
{
29✔
34
}
29✔
35

36
NetworkListener::NetworkListener() :
37
  d_data(std::make_shared<ListenerData>())
29✔
38
{
29✔
39
}
29✔
40

41
NetworkListener::~NetworkListener()
42
{
28✔
43
  d_data->d_exiting = true;
28✔
44

45
  /* wake up the listening thread */
46
  for (const auto& socket : d_data->d_sockets) {
28✔
47
    shutdown(socket.second.getHandle(), SHUT_RD);
22✔
48
  }
22✔
49
}
28✔
50

51
void NetworkListener::readCB(int desc, FDMultiplexer::funcparam_t& param)
52
{
335✔
53
  auto cbData = boost::any_cast<std::shared_ptr<NetworkListener::CBData>>(param);
335✔
54
  std::string packet;
335✔
55

56
#ifdef MSG_TRUNC
335✔
57
  /* first we peek to avoid allocating a very large buffer. "MSG_TRUNC [...] return the real length of the datagram, even when it was longer than the passed buffer" */
58
  auto peeked = recvfrom(desc, nullptr, 0, MSG_PEEK | MSG_TRUNC, nullptr, nullptr);
335✔
59
  if (peeked > 0) {
335✔
60
    packet.resize(static_cast<size_t>(peeked));
331✔
61
  }
331✔
62
#endif
335✔
63
  if (packet.empty()) {
335✔
64
    packet.resize(65535);
4✔
65
  }
4✔
66

67
  sockaddr_un from{};
335✔
68
  memset(&from, 0, sizeof(from));
335✔
69

70
  socklen_t fromLen = sizeof(from);
335✔
71
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
72
  auto got = recvfrom(desc, &packet.at(0), packet.size(), 0, reinterpret_cast<sockaddr*>(&from), &fromLen);
335✔
73
  if (got > 0) {
335✔
74
    packet.resize(static_cast<size_t>(got));
331✔
75
    std::string fromAddr;
331✔
76
    if (fromLen <= sizeof(from)) {
331!
77
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
78
      fromAddr = std::string(from.sun_path, strlen(from.sun_path));
331✔
79
    }
331✔
80
    try {
331✔
81
      cbData->d_cb(cbData->d_endpoint, std::move(packet), fromAddr);
331✔
82
    }
331✔
83
    catch (const std::exception& e) {
331✔
84
      vinfolog("Exception in the read callback of a NetworkListener: %s", e.what());
3!
85
    }
3✔
86
    catch (...) {
331✔
87
      vinfolog("Exception in the read callback of a NetworkListener");
3!
88
    }
3✔
89
  }
331✔
90
}
335✔
91

92
bool NetworkListener::addUnixListeningEndpoint(const std::string& path, NetworkListener::EndpointID endpointID, NetworkListener::NetworkDatagramCB callback)
93
{
32✔
94
  if (d_data->d_running) {
32✔
95
    throw std::runtime_error("NetworkListener should not be altered at runtime");
3✔
96
  }
3✔
97

98
  sockaddr_un sun{};
29✔
99
  if (makeUNsockaddr(path, &sun) != 0) {
29✔
100
    throw std::runtime_error("Invalid Unix socket path '" + path + "'");
3✔
101
  }
3✔
102

103
  bool abstractPath = path.at(0) == '\0';
26✔
104
  if (!abstractPath) {
26✔
105
    int err = unlink(path.c_str());
17✔
106
    if (err != 0) {
17✔
107
      err = errno;
2✔
108
      if (err != ENOENT) {
2!
109
        vinfolog("Error removing Unix socket to path '%s': %s", path, stringerror(err));
×
110
      }
×
111
    }
2✔
112
  }
17✔
113

114
  Socket sock(sun.sun_family, SOCK_DGRAM, 0);
26✔
115
  socklen_t sunLength = sizeof(sun);
26✔
116
  if (abstractPath) {
26✔
117
    /* abstract paths can contain null bytes so we need to set the actual size */
118
    sunLength = sizeof(sa_family_t) + path.size();
9✔
119
  }
9✔
120

121
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
122
  if (bind(sock.getHandle(), reinterpret_cast<const struct sockaddr*>(&sun), sunLength) != 0) {
26✔
123
    std::string sanitizedPath(path);
3✔
124
    if (abstractPath) {
3!
125
      sanitizedPath[0] = '@';
3✔
126
    }
3✔
127
    throw std::runtime_error("Error binding Unix socket to path '" + sanitizedPath + "': " + stringerror());
3✔
128
  }
3✔
129

130
  sock.setNonBlocking();
23✔
131

132
  auto cbData = std::make_shared<CBData>();
23✔
133
  cbData->d_endpoint = endpointID;
23✔
134
  cbData->d_cb = std::move(callback);
23✔
135
  d_data->d_mplexer->addReadFD(sock.getHandle(), readCB, cbData);
23✔
136

137
  d_data->d_sockets.insert({path, std::move(sock)});
23✔
138
  return true;
23✔
139
}
26✔
140

141
void NetworkListener::runOnce(ListenerData& data, timeval& now, uint32_t timeout)
142
{
338✔
143
  if (data.d_exiting) {
338!
144
    return;
×
145
  }
×
146

147
  dnsdist::configuration::refreshLocalRuntimeConfiguration();
338✔
148
  data.d_running = true;
338✔
149
  if (data.d_sockets.empty()) {
338✔
150
    throw runtime_error("NetworkListener started with no sockets");
3✔
151
  }
3✔
152

153
  data.d_mplexer->run(&now, static_cast<int>(timeout));
335✔
154
}
335✔
155

156
void NetworkListener::runOnce(timeval& now, uint32_t timeout)
157
{
18✔
158
  runOnce(*d_data, now, timeout);
18✔
159
}
18✔
160

161
void NetworkListener::mainThread(std::shared_ptr<ListenerData>& dataArg)
162
{
4✔
163
  /* take our own copy of the shared_ptr so it's still alive if the NetworkListener object
164
     gets destroyed while we are still running */
165
  // NOLINTNEXTLINE(performance-unnecessary-copy-initialization): we really need a copy here, or we end up with use-after-free as explained above
166
  auto data = dataArg;
4✔
167
  setThreadName("dnsdist/lua-net");
4✔
168
  timeval now{};
4✔
169

170
  while (!data->d_exiting) {
324✔
171
    runOnce(*data, now, -1);
320✔
172
  }
320✔
173
}
4✔
174

175
void NetworkListener::start()
176
{
4✔
177
  std::thread main = std::thread([this] {
4✔
178
    mainThread(d_data);
4✔
179
  });
4✔
180
  main.detach();
4✔
181
}
4✔
182

183
NetworkEndpoint::NetworkEndpoint(const std::string& path) :
184
  d_socket(AF_UNIX, SOCK_DGRAM, 0)
30✔
185
{
30✔
186
  sockaddr_un sun{};
30✔
187
  if (makeUNsockaddr(path, &sun) != 0) {
30✔
188
    throw std::runtime_error("Invalid Unix socket path '" + path + "'");
3✔
189
  }
3✔
190

191
  socklen_t sunLength = sizeof(sun);
27✔
192
  bool abstractPath = path.at(0) == '\0';
27✔
193

194
  if (abstractPath) {
27✔
195
    /* abstract paths can contain null bytes so we need to set the actual size */
196
    sunLength = sizeof(sa_family_t) + path.size();
6✔
197
  }
6✔
198
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
199
  if (connect(d_socket.getHandle(), reinterpret_cast<const struct sockaddr*>(&sun), sunLength) != 0) {
27✔
200
    std::string sanitizedPath(path);
7✔
201
    if (abstractPath) {
7✔
202
      sanitizedPath[0] = '@';
3✔
203
    }
3✔
204
    throw std::runtime_error("Error connecting Unix socket to path '" + sanitizedPath + "': " + stringerror());
7✔
205
  }
7✔
206

207
  d_socket.setNonBlocking();
20✔
208
}
20✔
209

210
bool NetworkEndpoint::send(const std::string_view& payload) const
211
{
384✔
212
  auto sent = ::send(d_socket.getHandle(), payload.data(), payload.size(), 0);
384✔
213
  if (sent <= 0) {
384!
214
    return false;
×
215
  }
×
216

217
  return static_cast<size_t>(sent) == payload.size();
384✔
218
}
384✔
219
}
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