Coverage Report

Created: 2026-05-24 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/addns/dnssock.c
Line
Count
Source
1
/*
2
  Linux DNS client library implementation
3
4
  Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5
  Copyright (C) 2006 Gerald Carter <jerry@samba.org>
6
7
     ** NOTE! The following LGPL license applies to the libaddns
8
     ** library. This does NOT imply that all of Samba is released
9
     ** under the LGPL
10
11
  This library is free software; you can redistribute it and/or
12
  modify it under the terms of the GNU Lesser General Public
13
  License as published by the Free Software Foundation; either
14
  version 2.1 of the License, or (at your option) any later version.
15
16
  This library is distributed in the hope that it will be useful,
17
  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
  Lesser General Public License for more details.
20
21
  You should have received a copy of the GNU Lesser General Public
22
  License along with this library; if not, see <http://www.gnu.org/licenses/>.
23
*/
24
25
#include "replace.h"
26
#include "dns.h"
27
#include <sys/time.h>
28
#include <unistd.h>
29
#include "system/select.h"
30
#include "../lib/util/debug.h"
31
32
static int destroy_dns_connection(struct dns_connection *conn)
33
0
{
34
0
  return close(conn->s);
35
0
}
36
37
/********************************************************************
38
********************************************************************/
39
40
static DNS_ERROR dns_open_helper(const char *nameserver,
41
         const char *service,
42
         struct addrinfo *hints,
43
         TALLOC_CTX *mem_ctx,
44
         struct dns_connection **ret_conn)
45
0
{
46
0
  int ret;
47
0
  struct addrinfo *rp;
48
0
  struct addrinfo *ai_result = NULL;
49
0
  struct dns_connection *conn = NULL;
50
51
0
  if (!(conn = talloc(mem_ctx, struct dns_connection))) {
52
0
    return ERROR_DNS_NO_MEMORY;
53
0
  }
54
55
0
  ret = getaddrinfo(nameserver, service, hints, &ai_result);
56
0
  if (ret != 0) {
57
0
    DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
58
0
    TALLOC_FREE(conn);
59
0
    return ERROR_DNS_INVALID_NAME_SERVER;
60
0
  }
61
62
0
  for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
63
0
    conn->s = socket(rp->ai_family,
64
0
        rp->ai_socktype,
65
0
        rp->ai_protocol);
66
0
    if (conn->s == -1) {
67
0
      continue;
68
0
    }
69
0
    do {
70
0
      ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
71
0
    } while ((ret == -1) && (errno == EINTR));
72
0
    if (ret != -1) {
73
      /* Successful connect */
74
0
      break;
75
0
    }
76
0
    close(conn->s);
77
0
  }
78
79
0
  freeaddrinfo(ai_result);
80
81
0
  if (rp == NULL) {
82
0
    TALLOC_FREE(conn);
83
0
    return ERROR_DNS_CONNECTION_FAILED;
84
0
  }
85
86
0
  talloc_set_destructor(conn, destroy_dns_connection);
87
88
0
  *ret_conn = conn;
89
0
  return ERROR_DNS_SUCCESS;
90
0
}
91
92
static DNS_ERROR dns_tcp_open( const char *nameserver,
93
             TALLOC_CTX *mem_ctx,
94
             struct dns_connection **result )
95
0
{
96
0
  struct addrinfo hints;
97
0
  struct dns_connection *conn;
98
0
  DNS_ERROR dns_ret;
99
0
  char service[16];
100
101
0
  snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
102
103
0
  memset(&hints, 0, sizeof(struct addrinfo));
104
0
  hints.ai_family = AF_UNSPEC;
105
0
  hints.ai_socktype = SOCK_STREAM;
106
0
  hints.ai_flags = 0;
107
0
  hints.ai_protocol = IPPROTO_TCP;
108
109
0
  dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
110
0
  if (!ERR_DNS_IS_OK(dns_ret)) {
111
0
    return dns_ret;
112
0
  }
113
114
0
  conn->hType = DNS_TCP;
115
0
  *result = conn;
116
0
  return ERROR_DNS_SUCCESS;
117
0
}
118
119
/********************************************************************
120
 * ********************************************************************/
121
122
static DNS_ERROR dns_udp_open( const char *nameserver,
123
             TALLOC_CTX *mem_ctx,
124
             struct dns_connection **result )
125
0
{
126
0
  struct addrinfo hints;
127
0
  struct sockaddr_storage RecvAddr;
128
0
  struct dns_connection *conn = NULL;
129
0
  DNS_ERROR dns_ret;
130
0
  socklen_t RecvAddrLen;
131
0
  char service[16];
132
133
0
  snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
134
135
0
  memset(&hints, 0, sizeof(struct addrinfo));
136
0
  hints.ai_family = AF_UNSPEC;
137
0
  hints.ai_socktype = SOCK_DGRAM;
138
0
  hints.ai_flags = 0;
139
0
  hints.ai_protocol = IPPROTO_UDP;
140
141
0
  dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
142
0
  if (!ERR_DNS_IS_OK(dns_ret)) {
143
0
    TALLOC_FREE(conn);
144
0
    return dns_ret;
145
0
  }
146
147
  /* Set up the RecvAddr structure with the IP address of
148
     the receiver and the specified port number. */
149
150
0
  RecvAddrLen = sizeof(RecvAddr);
151
0
  if (getpeername(conn->s,
152
0
      (struct sockaddr *)&RecvAddr,
153
0
      &RecvAddrLen) == -1) {
154
0
    return ERROR_DNS_CONNECTION_FAILED;
155
0
  }
156
157
0
  conn->hType = DNS_UDP;
158
0
  memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
159
160
0
  *result = conn;
161
0
  return ERROR_DNS_SUCCESS;
162
0
}
163
164
/********************************************************************
165
********************************************************************/
166
167
DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
168
        TALLOC_CTX *mem_ctx,
169
        struct dns_connection **conn )
170
0
{
171
0
  switch ( dwType ) {
172
0
  case DNS_TCP:
173
0
    return dns_tcp_open( nameserver, mem_ctx, conn );
174
0
  case DNS_UDP:
175
0
    return dns_udp_open( nameserver, mem_ctx, conn );
176
0
  }
177
178
0
  return ERROR_DNS_INVALID_PARAMETER;
179
0
}
180
181
static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
182
0
{
183
0
  size_t total = 0;
184
185
0
  while (total < len) {
186
187
0
    ssize_t ret;
188
189
0
    do {
190
0
      ret = write(fd, data + total, len - total);
191
0
    } while ((ret == -1) && (errno == EINTR));
192
193
0
    if (ret <= 0) {
194
      /*
195
       * EOF or error
196
       */
197
0
      return ERROR_DNS_SOCKET_ERROR;
198
0
    }
199
200
0
    total += ret;
201
0
  }
202
203
0
  return ERROR_DNS_SUCCESS;
204
0
}
205
206
static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
207
            const struct dns_buffer *buf)
208
0
{
209
0
  uint16_t len = htons(buf->offset);
210
0
  DNS_ERROR err;
211
212
0
  err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
213
0
  if (!ERR_DNS_IS_OK(err)) return err;
214
215
0
  return write_all(conn->s, buf->data, buf->offset);
216
0
}
217
218
static DNS_ERROR dns_send_udp(struct dns_connection *conn,
219
            const struct dns_buffer *buf)
220
0
{
221
0
  ssize_t ret;
222
223
0
  do {
224
0
    ret = send(conn->s, buf->data, buf->offset, 0);
225
0
  } while ((ret == -1) && (errno == EINTR));
226
227
0
  if (ret != buf->offset) {
228
0
    return ERROR_DNS_SOCKET_ERROR;
229
0
  }
230
231
0
  return ERROR_DNS_SUCCESS;
232
0
}
233
234
DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
235
0
{
236
0
  if (conn->hType == DNS_TCP) {
237
0
    return dns_send_tcp(conn, buf);
238
0
  }
239
240
0
  if (conn->hType == DNS_UDP) {
241
0
    return dns_send_udp(conn, buf);
242
0
  }
243
244
0
  return ERROR_DNS_INVALID_PARAMETER;
245
0
}
246
247
static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
248
0
{
249
0
  size_t total = 0;
250
251
0
  while (total < len) {
252
0
    struct pollfd pfd;
253
0
    ssize_t ret;
254
0
    int fd_ready;
255
256
0
    ZERO_STRUCT(pfd);
257
0
    pfd.fd = fd;
258
0
    pfd.events = POLLIN|POLLHUP;
259
260
0
    fd_ready = poll(&pfd, 1, 10000);
261
0
    if (fd_ready == -1) {
262
0
      if (errno == EINTR) {
263
0
        continue;
264
0
      }
265
0
      return ERROR_DNS_SOCKET_ERROR;
266
0
    }
267
0
    if ( fd_ready == 0 ) {
268
      /* read timeout */
269
0
      return ERROR_DNS_SOCKET_ERROR;
270
0
    }
271
272
0
    do {
273
0
      ret = read(fd, data + total, len - total);
274
0
    } while ((ret == -1) && (errno == EINTR));
275
276
0
    if (ret <= 0) {
277
      /* EOF or error */
278
0
      return ERROR_DNS_SOCKET_ERROR;
279
0
    }
280
281
0
    total += ret;
282
0
  }
283
284
0
  return ERROR_DNS_SUCCESS;
285
0
}
286
287
static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
288
         struct dns_connection *conn,
289
         struct dns_buffer **presult)
290
0
{
291
0
  struct dns_buffer *buf;
292
0
  DNS_ERROR err;
293
0
  uint16_t len;
294
295
0
  if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
296
0
    return ERROR_DNS_NO_MEMORY;
297
0
  }
298
299
0
  err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
300
0
  if (!ERR_DNS_IS_OK(err)) {
301
0
    return err;
302
0
  }
303
304
0
  buf->size = ntohs(len);
305
306
0
  if (buf->size == 0) {
307
0
    *presult = buf;
308
0
    return ERROR_DNS_SUCCESS;
309
0
  }
310
311
0
  if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
312
0
    TALLOC_FREE(buf);
313
0
    return ERROR_DNS_NO_MEMORY;
314
0
  }
315
316
0
  err = read_all(conn->s, buf->data, talloc_get_size(buf->data));
317
0
  if (!ERR_DNS_IS_OK(err)) {
318
0
    TALLOC_FREE(buf);
319
0
    return err;
320
0
  }
321
322
0
  *presult = buf;
323
0
  return ERROR_DNS_SUCCESS;
324
0
}
325
326
static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
327
         struct dns_connection *conn,
328
         struct dns_buffer **presult)
329
0
{
330
0
  struct dns_buffer *buf;
331
0
  ssize_t received;
332
333
0
  if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
334
0
    return ERROR_DNS_NO_MEMORY;
335
0
  }
336
337
  /*
338
   * UDP based DNS can only be 512 bytes
339
   */
340
341
0
  if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
342
0
    TALLOC_FREE(buf);
343
0
    return ERROR_DNS_NO_MEMORY;
344
0
  }
345
346
0
  do {
347
0
    received = recv(conn->s, (void *)buf->data, 512, 0);
348
0
  } while ((received == -1) && (errno == EINTR));
349
350
0
  if (received == -1) {
351
0
    TALLOC_FREE(buf);
352
0
    return ERROR_DNS_SOCKET_ERROR;
353
0
  }
354
355
0
  if (received > 512) {
356
0
    TALLOC_FREE(buf);
357
0
    return ERROR_DNS_BAD_RESPONSE;
358
0
  }
359
360
0
  buf->size = received;
361
0
  buf->offset = 0;
362
363
0
  *presult = buf;
364
0
  return ERROR_DNS_SUCCESS;
365
0
}
366
367
DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
368
          struct dns_buffer **presult)
369
0
{
370
0
  if (conn->hType == DNS_TCP) {
371
0
    return dns_receive_tcp(mem_ctx, conn, presult);
372
0
  }
373
374
0
  if (conn->hType == DNS_UDP) {
375
0
    return dns_receive_udp(mem_ctx, conn, presult);
376
0
  }
377
378
0
  return ERROR_DNS_INVALID_PARAMETER;
379
0
}
380
381
DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
382
        const struct dns_request *req,
383
        struct dns_request **resp)
384
0
{
385
0
  struct dns_buffer *buf = NULL;
386
0
  DNS_ERROR err;
387
388
0
  err = dns_marshall_request(mem_ctx, req, &buf);
389
0
  if (!ERR_DNS_IS_OK(err)) goto error;
390
391
0
  err = dns_send(conn, buf);
392
0
  if (!ERR_DNS_IS_OK(err)) goto error;
393
0
  TALLOC_FREE(buf);
394
395
0
  err = dns_receive(mem_ctx, conn, &buf);
396
0
  if (!ERR_DNS_IS_OK(err)) goto error;
397
398
0
  err = dns_unmarshall_request(mem_ctx, buf, resp);
399
400
0
 error:
401
0
  TALLOC_FREE(buf);
402
0
  return err;
403
0
}
404
405
DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
406
         struct dns_connection *conn,
407
         struct dns_update_request *up_req,
408
         struct dns_update_request **up_resp)
409
0
{
410
0
  struct dns_request *resp;
411
0
  DNS_ERROR err;
412
413
0
  err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
414
0
            &resp);
415
416
0
  if (!ERR_DNS_IS_OK(err)) return err;
417
418
0
  *up_resp = dns_request2update(resp);
419
0
  return ERROR_DNS_SUCCESS;
420
0
}