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

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

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

65.88
/pdns/recursordist/rec_channel.cc
1
#ifdef HAVE_CONFIG_H
2
#include "config.h"
3
#endif
4
#include "rec_channel.hh"
5
#include "utility.hh"
6
#include <sys/socket.h>
7
#include <cerrno>
8
#include "misc.hh"
9
#include <string.h>
10
#include <cstdlib>
11
#include <unistd.h>
12
#include <sys/types.h>
13
#include <sys/stat.h>
14
#include <iostream>
15
#include <limits.h>
16

17
#include "pdnsexception.hh"
18

19
#include "namespaces.hh"
20

21
std::atomic<bool> RecursorControlChannel::stop = false;
22

23
RecursorControlChannel::RecursorControlChannel()
24
{
632✔
25
  d_fd = -1;
632✔
26
  *d_local.sun_path = 0;
632✔
27
  d_local.sun_family = 0;
632✔
28
}
632✔
29

30
RecursorControlChannel::~RecursorControlChannel()
31
{
630✔
32
  if (d_fd > 0)
630!
33
    close(d_fd);
630✔
34
  if (*d_local.sun_path)
630✔
35
    unlink(d_local.sun_path);
153✔
36
}
630✔
37

38
int RecursorControlChannel::listen(const string& fname)
39
{
153✔
40
  d_fd = socket(AF_UNIX, SOCK_STREAM, 0);
153✔
41
  setCloseOnExec(d_fd);
153✔
42

43
  if (d_fd < 0)
153!
44
    throw PDNSException("Creating UNIX domain socket: " + stringerror());
×
45

46
  int tmp = 1;
153✔
47
  if (setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0)
153!
48
    throw PDNSException("Setsockopt failed: " + stringerror());
×
49

50
  int err = unlink(fname.c_str());
153✔
51
  if (err < 0 && errno != ENOENT)
153!
52
    throw PDNSException("Can't remove (previous) controlsocket '" + fname + "': " + stringerror() + " (try --socket-dir)");
×
53

54
  if (makeUNsockaddr(fname, &d_local))
153!
55
    throw PDNSException("Unable to bind to controlsocket, path '" + fname + "' is not a valid UNIX socket path.");
×
56

57
  if (bind(d_fd, (sockaddr*)&d_local, sizeof(d_local)) < 0)
153!
58
    throw PDNSException("Unable to bind to controlsocket '" + fname + "': " + stringerror());
×
59
  if (::listen(d_fd, 0) == -1) {
153!
60
    throw PDNSException("Unable to listen on controlsocket '" + fname + "': " + stringerror());
×
61
  }
×
62
  return d_fd;
153✔
63
}
153✔
64

65
void RecursorControlChannel::connect(const string& path, const string& fname)
66
{
477✔
67
  struct sockaddr_un remote;
477✔
68

69
  d_fd = socket(AF_UNIX, SOCK_STREAM, 0);
477✔
70
  setCloseOnExec(d_fd);
477✔
71

72
  if (d_fd < 0)
477!
73
    throw PDNSException("Creating UNIX domain socket: " + stringerror());
×
74

75
  try {
477✔
76
    int tmp = 1;
477✔
77
    if (setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0)
477!
78
      throw PDNSException("Setsockopt failed: " + stringerror());
×
79

80
    string remotename = path + "/" + fname;
477✔
81
    if (makeUNsockaddr(remotename, &remote))
477!
82
      throw PDNSException("Unable to connect to controlsocket, path '" + remotename + "' is not a valid UNIX socket path.");
×
83

84
    if (::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) {
477!
85
      if (*d_local.sun_path)
×
86
        unlink(d_local.sun_path);
×
87
      throw PDNSException("Unable to connect to remote '" + string(remote.sun_path) + "': " + stringerror());
×
88
    }
×
89
  }
477✔
90
  catch (...) {
477✔
91
    close(d_fd);
×
92
    d_fd = -1;
×
93
    d_local.sun_path[0] = 0;
×
94
    throw;
×
95
  }
×
96
}
477✔
97

98
static void sendfd(int s, int fd)
99
{
5✔
100
  struct msghdr msg;
5✔
101
  struct cmsghdr* cmsg;
5✔
102
  union
5✔
103
  {
5✔
104
    struct cmsghdr hdr;
5✔
105
    unsigned char buf[CMSG_SPACE(sizeof(int))];
5✔
106
  } cmsgbuf;
5✔
107
  struct iovec io_vector[1];
5✔
108
  char ch = 'X';
5✔
109

110
  io_vector[0].iov_base = &ch;
5✔
111
  io_vector[0].iov_len = 1;
5✔
112

113
  memset(&msg, 0, sizeof(msg));
5✔
114
  msg.msg_control = &cmsgbuf.buf;
5✔
115
  msg.msg_controllen = sizeof(cmsgbuf.buf);
5✔
116
  msg.msg_iov = io_vector;
5✔
117
  msg.msg_iovlen = 1;
5✔
118

119
  cmsg = CMSG_FIRSTHDR(&msg);
5✔
120
  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
5✔
121
  cmsg->cmsg_level = SOL_SOCKET;
5✔
122
  cmsg->cmsg_type = SCM_RIGHTS;
5✔
123
  *(int*)CMSG_DATA(cmsg) = fd;
5✔
124

125
  if (sendmsg(s, &msg, 0) == -1) {
5!
126
    throw PDNSException("Unable to send fd message over control channel: " + stringerror());
×
127
  }
×
128
}
5✔
129

130
void RecursorControlChannel::send(int fd, const Answer& msg, unsigned int timeout, int fd_to_pass)
131
{
941✔
132
  int ret = waitForRWData(fd, false, timeout, 0);
941✔
133
  if (ret == 0) {
941!
134
    throw PDNSException("Timeout sending message over control channel");
×
135
  }
×
136
  else if (ret < 0) {
941!
137
    throw PDNSException("Error sending message over control channel:" + stringerror());
×
138
  }
×
139

140
  if (::send(fd, &msg.d_ret, sizeof(msg.d_ret), 0) < 0) {
941!
141
    throw PDNSException("Unable to send return code over control channel: " + stringerror());
×
142
  }
×
143
  size_t len = msg.d_str.length();
941✔
144
  if (::send(fd, &len, sizeof(len), 0) < 0) {
941!
145
    throw PDNSException("Unable to send length over control channel: " + stringerror());
×
146
  }
×
147
  if (::send(fd, msg.d_str.c_str(), len, 0) != static_cast<ssize_t>(len)) {
941!
148
    throw PDNSException("Unable to send message over control channel: " + stringerror());
×
149
  }
×
150

151
  if (fd_to_pass != -1) {
941✔
152
    sendfd(fd, fd_to_pass);
5✔
153
  }
5✔
154
}
941✔
155

156
static void waitForRead(int fd, unsigned int timeout, time_t start)
157
{
3,007✔
158
  time_t elapsed = time(nullptr) - start;
3,007✔
159
  if (elapsed >= timeout) {
3,007!
160
    throw PDNSException("Timeout waiting for control channel data");
×
161
  }
×
162
  // coverity[store_truncates_time_t]
163
  int ret = waitForData(fd, timeout - elapsed, 0);
3,007✔
164
  if (ret == 0) {
3,007!
165
    throw PDNSException("Timeout waiting for control channel data");
×
166
  }
×
167
}
3,007✔
168

169
static size_t getArgMax()
170
{
941✔
171
#if defined(ARG_MAX)
172
  return ARG_MAX;
173
#endif
174

175
#if defined(_SC_ARG_MAX)
941✔
176
  auto tmp = sysconf(_SC_ARG_MAX);
941✔
177
  if (tmp != -1) {
941!
178
    return tmp;
941✔
179
  }
941✔
180
#endif
×
181
  /* _POSIX_ARG_MAX */
182
  return 4096;
×
183
}
941✔
184

185
RecursorControlChannel::Answer RecursorControlChannel::recv(int fd, unsigned int timeout)
186
{
941✔
187
  // timeout covers the operation of all read ops combined
188
  const time_t start = time(nullptr);
941✔
189

190
  waitForRead(fd, timeout, start);
941✔
191
  int err;
941✔
192
  if (::recv(fd, &err, sizeof(err), 0) != sizeof(err)) {
941!
193
    throw PDNSException("Unable to receive return status over control channel: " + stringerror());
×
194
  }
×
195

196
  waitForRead(fd, timeout, start);
941✔
197
  size_t len;
941✔
198
  if (::recv(fd, &len, sizeof(len), 0) != sizeof(len)) {
941!
199
    throw PDNSException("Unable to receive length over control channel: " + stringerror());
×
200
  }
×
201

202
  if (len > getArgMax()) {
941!
203
    throw PDNSException("Length of control channel message too large");
×
204
  }
×
205

206
  string str;
941✔
207
  str.reserve(len);
941✔
208
  while (str.length() < len) {
2,066✔
209
    char buffer[1024];
1,125✔
210
    waitForRead(fd, timeout, start);
1,125✔
211
    size_t toRead = std::min(len - str.length(), sizeof(buffer));
1,125✔
212
    ssize_t recvd = ::recv(fd, buffer, toRead, 0);
1,125✔
213
    if (recvd <= 0) {
1,125!
214
      // EOF means we have a length error
215
      throw PDNSException("Unable to receive message over control channel: " + stringerror());
×
216
    }
×
217
    str.append(buffer, recvd);
1,125✔
218
  }
1,125✔
219

220
  return {err, std::move(str)};
941✔
221
}
941✔
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