source: vendor/current/lib/addns/dnssock.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 9.8 KB
Line 
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
32static int destroy_dns_connection(struct dns_connection *conn)
33{
34 return close(conn->s);
35}
36
37/********************************************************************
38********************************************************************/
39
40static DNS_ERROR dns_tcp_open( const char *nameserver,
41 TALLOC_CTX *mem_ctx,
42 struct dns_connection **result )
43{
44 struct addrinfo hints;
45 struct addrinfo *ai_result = NULL;
46 struct addrinfo *rp;
47 struct dns_connection *conn;
48 int ret;
49 char service[16];
50
51 snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
52
53 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
54 return ERROR_DNS_NO_MEMORY;
55 }
56
57 memset(&hints, 0, sizeof(struct addrinfo));
58 hints.ai_family = AF_UNSPEC;
59 hints.ai_socktype = SOCK_STREAM;
60 hints.ai_flags = 0;
61 hints.ai_protocol = IPPROTO_TCP;
62
63 ret = getaddrinfo(nameserver, service, &hints, &ai_result);
64 if (ret != 0) {
65 DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
66 TALLOC_FREE(conn);
67 return ERROR_DNS_INVALID_NAME_SERVER;
68 }
69
70 for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
71 conn->s = socket(rp->ai_family,
72 rp->ai_socktype,
73 rp->ai_protocol);
74 if (conn->s == -1) {
75 continue;
76 }
77 do {
78 ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
79 } while ((ret == -1) && (errno == EINTR));
80 if (ret != -1) {
81 /* Successful connect */
82 break;
83 }
84 close(conn->s);
85 }
86
87 freeaddrinfo(ai_result);
88
89 /* Failed to connect with any address */
90 if (rp == NULL) {
91 TALLOC_FREE(conn);
92 return ERROR_DNS_CONNECTION_FAILED;
93 }
94
95 talloc_set_destructor(conn, destroy_dns_connection);
96
97 conn->hType = DNS_TCP;
98 *result = conn;
99 return ERROR_DNS_SUCCESS;
100}
101
102/********************************************************************
103 * ********************************************************************/
104
105static DNS_ERROR dns_udp_open( const char *nameserver,
106 TALLOC_CTX *mem_ctx,
107 struct dns_connection **result )
108{
109 struct addrinfo hints;
110 struct addrinfo *ai_result = NULL;
111 struct addrinfo *rp;
112 struct sockaddr_storage RecvAddr;
113 struct dns_connection *conn;
114 int ret;
115 socklen_t RecvAddrLen;
116 char service[16];
117
118 snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
119
120 if (!(conn = talloc(NULL, struct dns_connection))) {
121 return ERROR_DNS_NO_MEMORY;
122 }
123
124 memset(&hints, 0, sizeof(struct addrinfo));
125 hints.ai_family = AF_UNSPEC;
126 hints.ai_socktype = SOCK_DGRAM;
127 hints.ai_flags = 0;
128 hints.ai_protocol = IPPROTO_UDP;
129
130 ret = getaddrinfo(nameserver, service, &hints, &ai_result);
131 if (ret != 0) {
132 DEBUG(1,("dns_ucp_open:getaddrinfo: %s\n", gai_strerror(ret)));
133 TALLOC_FREE(conn);
134 return ERROR_DNS_INVALID_NAME_SERVER;
135 }
136
137 for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
138 conn->s = socket(rp->ai_family,
139 rp->ai_socktype,
140 rp->ai_protocol);
141 if (conn->s == -1) {
142 continue;
143 }
144 ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
145 if (ret != -1) {
146 /* Successful connect */
147 break;
148 }
149 close(conn->s);
150 }
151
152 freeaddrinfo(ai_result);
153
154 /* Failed to connect with any address */
155 if (rp == NULL) {
156 TALLOC_FREE(conn);
157 return ERROR_DNS_CONNECTION_FAILED;
158 }
159
160 talloc_set_destructor(conn, destroy_dns_connection);
161
162 /* Set up the RecvAddr structure with the IP address of
163 the receiver and the specified port number. */
164
165 RecvAddrLen = sizeof(RecvAddr);
166 if (getpeername(conn->s,
167 (struct sockaddr *)&RecvAddr,
168 &RecvAddrLen) == -1) {
169 TALLOC_FREE(conn);
170 return ERROR_DNS_CONNECTION_FAILED;
171 }
172
173 conn->hType = DNS_UDP;
174 memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
175
176 *result = conn;
177 return ERROR_DNS_SUCCESS;
178}
179
180/********************************************************************
181********************************************************************/
182
183DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
184 TALLOC_CTX *mem_ctx,
185 struct dns_connection **conn )
186{
187 switch ( dwType ) {
188 case DNS_TCP:
189 return dns_tcp_open( nameserver, mem_ctx, conn );
190 case DNS_UDP:
191 return dns_udp_open( nameserver, mem_ctx, conn );
192 }
193
194 return ERROR_DNS_INVALID_PARAMETER;
195}
196
197static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
198{
199 size_t total = 0;
200
201 while (total < len) {
202
203 ssize_t ret;
204
205 do {
206 ret = write(fd, data + total, len - total);
207 } while ((ret == -1) && (errno == EINTR));
208
209 if (ret <= 0) {
210 /*
211 * EOF or error
212 */
213 return ERROR_DNS_SOCKET_ERROR;
214 }
215
216 total += ret;
217 }
218
219 return ERROR_DNS_SUCCESS;
220}
221
222static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
223 const struct dns_buffer *buf)
224{
225 uint16_t len = htons(buf->offset);
226 DNS_ERROR err;
227
228 err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
229 if (!ERR_DNS_IS_OK(err)) return err;
230
231 return write_all(conn->s, buf->data, buf->offset);
232}
233
234static DNS_ERROR dns_send_udp(struct dns_connection *conn,
235 const struct dns_buffer *buf)
236{
237 ssize_t ret;
238
239 do {
240 ret = sendto(conn->s, buf->data, buf->offset, 0,
241 (struct sockaddr *)&conn->RecvAddr,
242 sizeof(conn->RecvAddr));
243 } while ((ret == -1) && (errno == EINTR));
244
245 if (ret != buf->offset) {
246 return ERROR_DNS_SOCKET_ERROR;
247 }
248
249 return ERROR_DNS_SUCCESS;
250}
251
252DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
253{
254 if (conn->hType == DNS_TCP) {
255 return dns_send_tcp(conn, buf);
256 }
257
258 if (conn->hType == DNS_UDP) {
259 return dns_send_udp(conn, buf);
260 }
261
262 return ERROR_DNS_INVALID_PARAMETER;
263}
264
265static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
266{
267 size_t total = 0;
268
269 while (total < len) {
270 struct pollfd pfd;
271 ssize_t ret;
272 int fd_ready;
273
274 ZERO_STRUCT(pfd);
275 pfd.fd = fd;
276 pfd.events = POLLIN|POLLHUP;
277
278 fd_ready = poll(&pfd, 1, 10000);
279 if (fd_ready == -1) {
280 if (errno == EINTR) {
281 continue;
282 }
283 return ERROR_DNS_SOCKET_ERROR;
284 }
285 if ( fd_ready == 0 ) {
286 /* read timeout */
287 return ERROR_DNS_SOCKET_ERROR;
288 }
289
290 do {
291 ret = read(fd, data + total, len - total);
292 } while ((ret == -1) && (errno == EINTR));
293
294 if (ret <= 0) {
295 /* EOF or error */
296 return ERROR_DNS_SOCKET_ERROR;
297 }
298
299 total += ret;
300 }
301
302 return ERROR_DNS_SUCCESS;
303}
304
305static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
306 struct dns_connection *conn,
307 struct dns_buffer **presult)
308{
309 struct dns_buffer *buf;
310 DNS_ERROR err;
311 uint16_t len;
312
313 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
314 return ERROR_DNS_NO_MEMORY;
315 }
316
317 err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
318 if (!ERR_DNS_IS_OK(err)) {
319 return err;
320 }
321
322 buf->size = ntohs(len);
323
324 if (buf->size == 0) {
325 *presult = buf;
326 return ERROR_DNS_SUCCESS;
327 }
328
329 if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
330 TALLOC_FREE(buf);
331 return ERROR_DNS_NO_MEMORY;
332 }
333
334 err = read_all(conn->s, buf->data, talloc_get_size(buf->data));
335 if (!ERR_DNS_IS_OK(err)) {
336 TALLOC_FREE(buf);
337 return err;
338 }
339
340 *presult = buf;
341 return ERROR_DNS_SUCCESS;
342}
343
344static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
345 struct dns_connection *conn,
346 struct dns_buffer **presult)
347{
348 struct dns_buffer *buf;
349 ssize_t received;
350
351 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
352 return ERROR_DNS_NO_MEMORY;
353 }
354
355 /*
356 * UDP based DNS can only be 512 bytes
357 */
358
359 if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
360 TALLOC_FREE(buf);
361 return ERROR_DNS_NO_MEMORY;
362 }
363
364 do {
365 received = recv(conn->s, (void *)buf->data, 512, 0);
366 } while ((received == -1) && (errno == EINTR));
367
368 if (received == -1) {
369 TALLOC_FREE(buf);
370 return ERROR_DNS_SOCKET_ERROR;
371 }
372
373 if (received > 512) {
374 TALLOC_FREE(buf);
375 return ERROR_DNS_BAD_RESPONSE;
376 }
377
378 buf->size = received;
379 buf->offset = 0;
380
381 *presult = buf;
382 return ERROR_DNS_SUCCESS;
383}
384
385DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
386 struct dns_buffer **presult)
387{
388 if (conn->hType == DNS_TCP) {
389 return dns_receive_tcp(mem_ctx, conn, presult);
390 }
391
392 if (conn->hType == DNS_UDP) {
393 return dns_receive_udp(mem_ctx, conn, presult);
394 }
395
396 return ERROR_DNS_INVALID_PARAMETER;
397}
398
399DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
400 const struct dns_request *req,
401 struct dns_request **resp)
402{
403 struct dns_buffer *buf = NULL;
404 DNS_ERROR err;
405
406 err = dns_marshall_request(mem_ctx, req, &buf);
407 if (!ERR_DNS_IS_OK(err)) goto error;
408
409 err = dns_send(conn, buf);
410 if (!ERR_DNS_IS_OK(err)) goto error;
411 TALLOC_FREE(buf);
412
413 err = dns_receive(mem_ctx, conn, &buf);
414 if (!ERR_DNS_IS_OK(err)) goto error;
415
416 err = dns_unmarshall_request(mem_ctx, buf, resp);
417
418 error:
419 TALLOC_FREE(buf);
420 return err;
421}
422
423DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
424 struct dns_connection *conn,
425 struct dns_update_request *up_req,
426 struct dns_update_request **up_resp)
427{
428 struct dns_request *resp;
429 DNS_ERROR err;
430
431 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
432 &resp);
433
434 if (!ERR_DNS_IS_OK(err)) return err;
435
436 *up_resp = dns_request2update(resp);
437 return ERROR_DNS_SUCCESS;
438}
Note: See TracBrowser for help on using the repository browser.