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

PowerDNS / pdns / 9498012098

13 Jun 2024 10:27AM UTC coverage: 61.22% (-3.4%) from 64.615%
9498012098

Pull #14325

github

web-flow
Merge e3409d021 into 57ab0fbc9
Pull Request #14325: Set nsec3param: first increase the serial and then rectify

34064 of 88172 branches covered (38.63%)

Branch coverage included in aggregate %.

5 of 7 new or added lines in 1 file covered. (71.43%)

5415 existing lines in 81 files now uncovered.

118803 of 161528 relevant lines covered (73.55%)

4993315.9 hits per line

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

59.53
/pdns/sstuff.hh
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
#pragma once
23
#include <string>
24
#include <sstream>
25
#include <iostream>
26
#include "iputils.hh"
27
#include <cerrno>
28
#include <sys/types.h>
29
#include <unistd.h>
30
#include <sys/socket.h>
31
#include <netinet/in.h>
32
#include <netinet/tcp.h>
33
#include <arpa/inet.h>
34
#include <sys/select.h>
35
#include <fcntl.h>
36
#include <stdexcept>
37

38
#include <boost/utility.hpp>
39
#include <csignal>
40
#include "namespaces.hh"
41
#include "noinitvector.hh"
42

43
using ProtocolType = int; //!< Supported protocol types
44

45
//! Representation of a Socket and many of the Berkeley functions available
46
class Socket : public boost::noncopyable
47
{
48
public:
49
  Socket(int fd): d_socket(fd)
50
  {
7,718✔
51
  }
7,718✔
52

53
  //! Construct a socket of specified address family and socket type.
54
  Socket(int af, int st, ProtocolType pt=0)
55
  {
53,343✔
56
    if((d_socket=socket(af, st, pt))<0)
53,343!
57
      throw NetworkError(stringerror());
×
58
    setCloseOnExec(d_socket);
53,343✔
59
  }
53,343✔
60

61
  Socket(Socket&& rhs) noexcept :
62
    d_buffer(std::move(rhs.d_buffer)), d_socket(rhs.d_socket)
63
  {
1,023✔
64
    rhs.d_socket = -1;
1,023✔
65
  }
1,023✔
66

67
  Socket& operator=(Socket&& rhs) noexcept
68
  {
1,114✔
69
    if (d_socket != -1) {
1,114!
70
      close(d_socket);
×
71
    }
×
72
    d_socket = rhs.d_socket;
1,114✔
73
    rhs.d_socket = -1;
1,114✔
74
    d_buffer = std::move(rhs.d_buffer);
1,114✔
75
    return *this;
1,114✔
76
  }
1,114✔
77

78
  ~Socket()
79
  {
83,064✔
80
    try {
83,064✔
81
      if (d_socket != -1) {
83,064✔
82
        closesocket(d_socket);
34,789✔
83
      }
34,789✔
84
    }
83,064✔
85
    catch(const PDNSException& e) {
83,064✔
86
    }
×
87
  }
83,064✔
88

89
  //! If the socket is capable of doing so, this function will wait for a connection
90
  std::unique_ptr<Socket> accept()
91
  {
1,528✔
92
    struct sockaddr_in remote;
1,528✔
93
    socklen_t remlen=sizeof(remote);
1,528✔
94
    memset(&remote, 0, sizeof(remote));
1,528✔
95
    int s=::accept(d_socket, reinterpret_cast<sockaddr *>(&remote), &remlen);
1,528✔
96
    if(s<0) {
1,528!
97
      if(errno==EAGAIN)
×
98
        return nullptr;
×
99

100
      throw NetworkError("Accepting a connection: "+stringerror());
×
101
    }
×
102

103
    return std::make_unique<Socket>(s);
1,528✔
104
  }
1,528✔
105

106
  //! Get remote address
107
  bool getRemote(ComboAddress &remote) {
3,028✔
108
    socklen_t remotelen=sizeof(remote);
3,028✔
109
    return (getpeername(d_socket, reinterpret_cast<struct sockaddr *>(&remote), &remotelen) >= 0);
3,028✔
110
  }
3,028✔
111

112
  //! Check remote address against netmaskgroup ng
113
  bool acl(const NetmaskGroup &ng)
114
  {
1,514✔
115
    ComboAddress remote;
1,514✔
116
    if (getRemote(remote))
1,514!
117
      return ng.match(remote);
1,514✔
118

119
    return false;
×
120
  }
1,514✔
121

122
  //! Set the socket to non-blocking
123
  void setNonBlocking()
124
  {
33,327✔
125
    ::setNonBlocking(d_socket);
33,327✔
126
  }
33,327✔
127

128
  //! Set the socket to blocking
129
  void setBlocking()
130
  {
5✔
131
    ::setBlocking(d_socket);
5✔
132
  }
5✔
133

134
  void setReuseAddr()
135
  {
39✔
136
    try {
39✔
137
      ::setReuseAddr(d_socket);
39✔
138
    } catch (const PDNSException &e) {
39✔
139
      throw NetworkError(e.reason);
×
140
    }
×
141
  }
39✔
142

143
  void setFastOpenConnect()
144
  {
×
145
#ifdef TCP_FASTOPEN_CONNECT
×
146
    int on = 1;
×
147
    if (setsockopt(d_socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &on, sizeof(on)) < 0) {
×
148
      throw NetworkError("While setting TCP_FASTOPEN_CONNECT: " + stringerror());
×
149
    }
×
150
#else
151
   throw NetworkError("While setting TCP_FASTOPEN_CONNECT: not compiled in");
152
#endif
153
  }
×
154

155
  //! Bind the socket to a specified endpoint
156
  void bind(const ComboAddress &local, bool reuseaddr=true)
157
  {
365✔
158
    int tmp=1;
365✔
159
    if(reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp)<0)
365!
160
      throw NetworkError("Setsockopt failed: "+stringerror());
×
161

162
    if(::bind(d_socket, reinterpret_cast<const struct sockaddr *>(&local), local.getSocklen())<0)
365!
163
      throw NetworkError("While binding: "+stringerror());
×
164
  }
365✔
165

166
  //! Connect the socket to a specified endpoint
167
  void connect(const ComboAddress &ep, int timeout=0)
168
  {
20,271✔
169
    SConnectWithTimeout(d_socket, ep, timeval{timeout,0});
20,271✔
170
  }
20,271✔
171

172

173
  //! For datagram sockets, receive a datagram and learn where it came from
174
  /** For datagram sockets, receive a datagram and learn where it came from
175
      \param dgram Will be filled with the datagram
176
      \param ep Will be filled with the origin of the datagram */
177
  void recvFrom(string &dgram, ComboAddress& remote)
178
  {
179
    socklen_t remlen = sizeof(remote);
180
    if (dgram.size() < s_buflen) {
181
      dgram.resize(s_buflen);
182
    }
183
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
184
    auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote) , &remlen);
185
    if (bytes < 0) {
186
      throw NetworkError("After recvfrom: " + stringerror());
187
    }
188
    dgram.resize(static_cast<size_t>(bytes));
189
  }
190

191
  bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote)
192
  {
×
193
    socklen_t remlen = sizeof(remote);
×
194
    if (dgram.size() < s_buflen) {
×
195
      dgram.resize(s_buflen);
×
196
    }
×
197
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
×
198
    auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote), &remlen);
×
199
    if (bytes < 0) {
×
200
      if (errno != EAGAIN) {
×
201
        throw NetworkError("After async recvfrom: " + stringerror());
×
202
      }
×
203
      else {
×
204
        return false;
×
205
      }
×
206
    }
×
207
    dgram.resize(static_cast<size_t>(bytes));
×
208
    return true;
×
209
  }
×
210

211
  //! For datagram sockets, send a datagram to a destination
212
  void sendTo(const char* msg, size_t len, const ComboAddress& remote)
213
  {
214
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
215
    if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&remote), remote.getSocklen()) < 0) {
216
      throw NetworkError("After sendto: " + stringerror());
217
    }
218
  }
219

220
  //! For connected datagram sockets, send a datagram
221
  void send(const std::string& msg)
222
  {
311✔
223
    if (::send(d_socket, msg.data(), msg.size(), 0) < 0) {
311!
224
      throw NetworkError("After send: "+stringerror());
×
225
    }
×
226
  }
311✔
227

228

229
  /** For datagram sockets, send a datagram to a destination
230
      \param dgram The datagram
231
      \param remote The intended destination of the datagram */
232
  void sendTo(const string& dgram, const ComboAddress& remote)
233
  {
234
    sendTo(dgram.data(), dgram.length(), remote);
235
  }
236

237

238
  //! Write this data to the socket, taking care that all bytes are written out
239
  void writen(const string &data)
240
  {
16✔
241
    if(data.empty())
16!
242
      return;
243

244
    size_t toWrite=data.length();
16✔
245
    ssize_t res;
16✔
246
    const char *ptr=data.c_str();
16✔
247

248
    do {
16✔
249
      res=::send(d_socket, ptr, toWrite, 0);
16✔
250
      if(res<0)
16!
251
        throw NetworkError("Writing to a socket: "+stringerror());
252
      if(!res)
16!
253
        throw NetworkError("EOF on socket");
254
      toWrite -= static_cast<size_t>(res);
16✔
255
      ptr += static_cast<size_t>(res);
16✔
256
    } while(toWrite);
16!
257

258
  }
16✔
259

260
  //! tries to write toWrite bytes from ptr to the socket
261
  /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
262
      \param ptr Location to write from
263
      \param toWrite number of bytes to try
264
  */
265
  size_t tryWrite(const char *ptr, size_t toWrite)
266
  {
×
267
    ssize_t res;
×
268
    res=::send(d_socket,ptr,toWrite,0);
×
269
    if(res==0)
×
270
      throw NetworkError("EOF on writing to a socket");
×
271

×
272
    if(res>0)
×
273
      return res;
×
274

×
275
    if(errno==EAGAIN)
×
276
      return 0;
×
277

×
278
    throw NetworkError("Writing to a socket: "+stringerror());
×
279
  }
×
280

281
  //! Writes toWrite bytes from ptr to the socket
282
  /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
283
  size_t write(const char *ptr, size_t toWrite)
284
  {
285
    ssize_t res;
286
    res=::send(d_socket,ptr,toWrite,0);
287
    if(res<0) {
288
      throw NetworkError("Writing to a socket: "+stringerror());
289
    }
290
    return res;
291
  }
292

293
  void writenWithTimeout(const void *buffer, size_t n, int timeout)
294
  {
1,755✔
295
    size_t bytes=n;
1,755✔
296
    const char *ptr = reinterpret_cast<const char*>(buffer);
1,755✔
297
    ssize_t ret;
1,755✔
298
    while(bytes) {
3,518✔
299
      ret=::write(d_socket, ptr, bytes);
1,763✔
300
      if(ret < 0) {
1,763✔
301
        if(errno == EAGAIN) {
4!
302
          ret=waitForRWData(d_socket, false, timeout, 0);
4✔
303
          if(ret < 0)
4!
304
            throw NetworkError("Waiting for data write");
×
305
          if(!ret)
4!
306
            throw NetworkError("Timeout writing data");
×
307
          continue;
4✔
308
        }
4✔
309
        else
×
310
          throw NetworkError("Writing data: "+stringerror());
×
311
      }
4✔
312
      if(!ret) {
1,759!
313
        throw NetworkError("Did not fulfill TCP write due to EOF");
×
314
      }
×
315

316
      ptr += static_cast<size_t>(ret);
1,759✔
317
      bytes -= static_cast<size_t>(ret);
1,759✔
318
    }
1,759✔
319
  }
1,755✔
320

321
  //! reads one character from the socket
322
  int getChar()
323
  {
×
324
    char c;
×
325

×
326
    ssize_t res=::recv(d_socket,&c,1,0);
×
327
    if(res)
×
328
      return c;
×
329
    return -1;
×
330
  }
×
331

332
  void getline(string &data)
333
  {
×
334
    data="";
×
335
    int c;
×
336
    while((c=getChar())!=-1) {
×
337
      data+=(char)c;
×
338
      if(c=='\n')
×
339
        break;
×
340
    }
×
341
  }
×
342

343
  //! Reads a block of data from the socket to a string
344
  void read(string &data)
345
  {
311✔
346
    d_buffer.resize(s_buflen);
311✔
347
    ssize_t res=::recv(d_socket, &d_buffer[0], s_buflen, 0);
311✔
348
    if(res<0)
311!
UNCOV
349
      throw NetworkError("Reading from a socket: "+stringerror());
×
350
    data.assign(d_buffer, 0, static_cast<size_t>(res));
311✔
351
  }
311✔
352

353
  //! Reads a block of data from the socket to a block of memory
354
  size_t read(char *buffer, size_t bytes)
355
  {
27,642✔
356
    ssize_t res=::recv(d_socket, buffer, bytes, 0);
27,642✔
357
    if(res<0)
27,642✔
358
      throw NetworkError("Reading from a socket: "+stringerror());
4✔
359
    return static_cast<size_t>(res);
27,638✔
360
  }
27,642✔
361

362
  /** Read a bock of data from the socket to a block of memory,
363
  *   waiting at most 'timeout' seconds for the data to become
364
  *   available. Be aware that this does _NOT_ handle partial reads
365
  *   for you.
366
  */
367
  ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
368
  {
1,954✔
369
    int err = waitForRWData(d_socket, true, timeout, 0);
1,954✔
370

371
    if(err == 0)
1,954!
372
      throw NetworkError("timeout reading");
×
373
    if(err < 0)
1,954!
374
      throw NetworkError("nonblocking read failed: "+stringerror());
×
375

376
    return read(buffer, n);
1,954✔
377
  }
1,954✔
378

379
  //! Sets the socket to listen with a default listen backlog of 10 pending connections
380
  void listen(unsigned int length=10)
381
  {
71✔
382
    if(::listen(d_socket,length)<0)
71!
383
      throw NetworkError("Setting socket to listen: "+stringerror());
×
384
  }
71✔
385

386
  //! Returns the internal file descriptor of the socket
387
  int getHandle() const
388
  {
136,986✔
389
    return d_socket;
136,986✔
390
  }
136,986✔
391

392
  int releaseHandle()
393
  {
7,275✔
394
    int ret = d_socket;
7,275✔
395
    d_socket = -1;
7,275✔
396
    return ret;
7,275✔
397
  }
7,275✔
398

399
private:
400
  static const size_t s_buflen{4096};
401
  std::string d_buffer;
402
  int d_socket;
403
};
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