2 Linux DNS client library implementation
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
7 ** NOTE! The following LGPL license applies to the libaddns
8 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
29 #include "system/select.h"
30 #include "../lib/util/debug.h"
32 static int destroy_dns_connection(struct dns_connection
*conn
)
34 return close(conn
->s
);
37 /********************************************************************
38 ********************************************************************/
40 static DNS_ERROR
dns_open_helper(const char *nameserver
,
42 struct addrinfo
*hints
,
44 struct dns_connection
**ret_conn
)
48 struct addrinfo
*ai_result
= NULL
;
49 struct dns_connection
*conn
= NULL
;
51 if (!(conn
= talloc(mem_ctx
, struct dns_connection
))) {
52 return ERROR_DNS_NO_MEMORY
;
55 ret
= getaddrinfo(nameserver
, service
, hints
, &ai_result
);
57 DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret
)));
59 return ERROR_DNS_INVALID_NAME_SERVER
;
62 for (rp
= ai_result
; rp
!= NULL
; rp
= rp
->ai_next
) {
63 conn
->s
= socket(rp
->ai_family
,
70 ret
= connect(conn
->s
, rp
->ai_addr
, rp
->ai_addrlen
);
71 } while ((ret
== -1) && (errno
== EINTR
));
73 /* Successful connect */
79 freeaddrinfo(ai_result
);
83 return ERROR_DNS_CONNECTION_FAILED
;
86 talloc_set_destructor(conn
, destroy_dns_connection
);
89 return ERROR_DNS_SUCCESS
;
92 static DNS_ERROR
dns_tcp_open( const char *nameserver
,
94 struct dns_connection
**result
)
96 struct addrinfo hints
;
97 struct dns_connection
*conn
;
101 snprintf(service
, sizeof(service
), "%d", DNS_TCP_PORT
);
103 memset(&hints
, 0, sizeof(struct addrinfo
));
104 hints
.ai_family
= AF_UNSPEC
;
105 hints
.ai_socktype
= SOCK_STREAM
;
107 hints
.ai_protocol
= IPPROTO_TCP
;
109 dns_ret
= dns_open_helper(nameserver
, service
, &hints
, mem_ctx
, &conn
);
110 if (!ERR_DNS_IS_OK(dns_ret
)) {
114 conn
->hType
= DNS_TCP
;
116 return ERROR_DNS_SUCCESS
;
119 /********************************************************************
120 * ********************************************************************/
122 static DNS_ERROR
dns_udp_open( const char *nameserver
,
124 struct dns_connection
**result
)
126 struct addrinfo hints
;
127 struct sockaddr_storage RecvAddr
;
128 struct dns_connection
*conn
= NULL
;
130 socklen_t RecvAddrLen
;
133 snprintf(service
, sizeof(service
), "%d", DNS_UDP_PORT
);
135 memset(&hints
, 0, sizeof(struct addrinfo
));
136 hints
.ai_family
= AF_UNSPEC
;
137 hints
.ai_socktype
= SOCK_DGRAM
;
139 hints
.ai_protocol
= IPPROTO_UDP
;
141 dns_ret
= dns_open_helper(nameserver
, service
, &hints
, mem_ctx
, &conn
);
142 if (!ERR_DNS_IS_OK(dns_ret
)) {
147 /* Set up the RecvAddr structure with the IP address of
148 the receiver and the specified port number. */
150 RecvAddrLen
= sizeof(RecvAddr
);
151 if (getpeername(conn
->s
,
152 (struct sockaddr
*)&RecvAddr
,
153 &RecvAddrLen
) == -1) {
154 return ERROR_DNS_CONNECTION_FAILED
;
157 conn
->hType
= DNS_UDP
;
158 memcpy(&conn
->RecvAddr
, &RecvAddr
, sizeof(struct sockaddr_storage
));
161 return ERROR_DNS_SUCCESS
;
164 /********************************************************************
165 ********************************************************************/
167 DNS_ERROR
dns_open_connection( const char *nameserver
, int32_t dwType
,
169 struct dns_connection
**conn
)
173 return dns_tcp_open( nameserver
, mem_ctx
, conn
);
175 return dns_udp_open( nameserver
, mem_ctx
, conn
);
178 return ERROR_DNS_INVALID_PARAMETER
;
181 static DNS_ERROR
write_all(int fd
, uint8_t *data
, size_t len
)
185 while (total
< len
) {
190 ret
= write(fd
, data
+ total
, len
- total
);
191 } while ((ret
== -1) && (errno
== EINTR
));
197 return ERROR_DNS_SOCKET_ERROR
;
203 return ERROR_DNS_SUCCESS
;
206 static DNS_ERROR
dns_send_tcp(struct dns_connection
*conn
,
207 const struct dns_buffer
*buf
)
209 uint16_t len
= htons(buf
->offset
);
212 err
= write_all(conn
->s
, (uint8_t *)&len
, sizeof(len
));
213 if (!ERR_DNS_IS_OK(err
)) return err
;
215 return write_all(conn
->s
, buf
->data
, buf
->offset
);
218 static DNS_ERROR
dns_send_udp(struct dns_connection
*conn
,
219 const struct dns_buffer
*buf
)
224 ret
= send(conn
->s
, buf
->data
, buf
->offset
, 0);
225 } while ((ret
== -1) && (errno
== EINTR
));
227 if (ret
!= buf
->offset
) {
228 return ERROR_DNS_SOCKET_ERROR
;
231 return ERROR_DNS_SUCCESS
;
234 DNS_ERROR
dns_send(struct dns_connection
*conn
, const struct dns_buffer
*buf
)
236 if (conn
->hType
== DNS_TCP
) {
237 return dns_send_tcp(conn
, buf
);
240 if (conn
->hType
== DNS_UDP
) {
241 return dns_send_udp(conn
, buf
);
244 return ERROR_DNS_INVALID_PARAMETER
;
247 static DNS_ERROR
read_all(int fd
, uint8_t *data
, size_t len
)
251 while (total
< len
) {
258 pfd
.events
= POLLIN
|POLLHUP
;
260 fd_ready
= poll(&pfd
, 1, 10000);
261 if (fd_ready
== -1) {
262 if (errno
== EINTR
) {
265 return ERROR_DNS_SOCKET_ERROR
;
267 if ( fd_ready
== 0 ) {
269 return ERROR_DNS_SOCKET_ERROR
;
273 ret
= read(fd
, data
+ total
, len
- total
);
274 } while ((ret
== -1) && (errno
== EINTR
));
278 return ERROR_DNS_SOCKET_ERROR
;
284 return ERROR_DNS_SUCCESS
;
287 static DNS_ERROR
dns_receive_tcp(TALLOC_CTX
*mem_ctx
,
288 struct dns_connection
*conn
,
289 struct dns_buffer
**presult
)
291 struct dns_buffer
*buf
;
295 if (!(buf
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
296 return ERROR_DNS_NO_MEMORY
;
299 err
= read_all(conn
->s
, (uint8_t *)&len
, sizeof(len
));
300 if (!ERR_DNS_IS_OK(err
)) {
304 buf
->size
= ntohs(len
);
306 if (buf
->size
== 0) {
308 return ERROR_DNS_SUCCESS
;
311 if (!(buf
->data
= talloc_array(buf
, uint8_t, buf
->size
))) {
313 return ERROR_DNS_NO_MEMORY
;
316 err
= read_all(conn
->s
, buf
->data
, talloc_get_size(buf
->data
));
317 if (!ERR_DNS_IS_OK(err
)) {
323 return ERROR_DNS_SUCCESS
;
326 static DNS_ERROR
dns_receive_udp(TALLOC_CTX
*mem_ctx
,
327 struct dns_connection
*conn
,
328 struct dns_buffer
**presult
)
330 struct dns_buffer
*buf
;
333 if (!(buf
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
334 return ERROR_DNS_NO_MEMORY
;
338 * UDP based DNS can only be 512 bytes
341 if (!(buf
->data
= talloc_array(buf
, uint8_t, 512))) {
343 return ERROR_DNS_NO_MEMORY
;
347 received
= recv(conn
->s
, (void *)buf
->data
, 512, 0);
348 } while ((received
== -1) && (errno
== EINTR
));
350 if (received
== -1) {
352 return ERROR_DNS_SOCKET_ERROR
;
355 if (received
> 512) {
357 return ERROR_DNS_BAD_RESPONSE
;
360 buf
->size
= received
;
364 return ERROR_DNS_SUCCESS
;
367 DNS_ERROR
dns_receive(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
368 struct dns_buffer
**presult
)
370 if (conn
->hType
== DNS_TCP
) {
371 return dns_receive_tcp(mem_ctx
, conn
, presult
);
374 if (conn
->hType
== DNS_UDP
) {
375 return dns_receive_udp(mem_ctx
, conn
, presult
);
378 return ERROR_DNS_INVALID_PARAMETER
;
381 DNS_ERROR
dns_transaction(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
382 const struct dns_request
*req
,
383 struct dns_request
**resp
)
385 struct dns_buffer
*buf
= NULL
;
388 err
= dns_marshall_request(mem_ctx
, req
, &buf
);
389 if (!ERR_DNS_IS_OK(err
)) goto error
;
391 err
= dns_send(conn
, buf
);
392 if (!ERR_DNS_IS_OK(err
)) goto error
;
395 err
= dns_receive(mem_ctx
, conn
, &buf
);
396 if (!ERR_DNS_IS_OK(err
)) goto error
;
398 err
= dns_unmarshall_request(mem_ctx
, buf
, 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
)
410 struct dns_request
*resp
;
413 err
= dns_transaction(mem_ctx
, conn
, dns_update2request(up_req
),
416 if (!ERR_DNS_IS_OK(err
)) return err
;
418 *up_resp
= dns_request2update(resp
);
419 return ERROR_DNS_SUCCESS
;