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