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_tcp_open( const char *nameserver
,
42 struct dns_connection
**result
)
44 struct addrinfo hints
;
45 struct addrinfo
*ai_result
= NULL
;
47 struct dns_connection
*conn
;
51 snprintf(service
, sizeof(service
), "%d", DNS_TCP_PORT
);
53 if (!(conn
= talloc(mem_ctx
, struct dns_connection
))) {
54 return ERROR_DNS_NO_MEMORY
;
57 memset(&hints
, 0, sizeof(struct addrinfo
));
58 hints
.ai_family
= AF_UNSPEC
;
59 hints
.ai_socktype
= SOCK_STREAM
;
61 hints
.ai_protocol
= IPPROTO_TCP
;
63 ret
= getaddrinfo(nameserver
, service
, &hints
, &ai_result
);
65 DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret
)));
67 return ERROR_DNS_INVALID_NAME_SERVER
;
70 for (rp
= ai_result
; rp
!= NULL
; rp
= rp
->ai_next
) {
71 conn
->s
= socket(rp
->ai_family
,
78 ret
= connect(conn
->s
, rp
->ai_addr
, rp
->ai_addrlen
);
79 } while ((ret
== -1) && (errno
== EINTR
));
81 /* Successful connect */
87 freeaddrinfo(ai_result
);
89 /* Failed to connect with any address */
92 return ERROR_DNS_CONNECTION_FAILED
;
95 talloc_set_destructor(conn
, destroy_dns_connection
);
97 conn
->hType
= DNS_TCP
;
99 return ERROR_DNS_SUCCESS
;
102 /********************************************************************
103 * ********************************************************************/
105 static DNS_ERROR
dns_udp_open( const char *nameserver
,
107 struct dns_connection
**result
)
109 struct addrinfo hints
;
110 struct addrinfo
*ai_result
= NULL
;
112 struct sockaddr_storage RecvAddr
;
113 struct dns_connection
*conn
;
115 socklen_t RecvAddrLen
;
118 snprintf(service
, sizeof(service
), "%d", DNS_UDP_PORT
);
120 if (!(conn
= talloc(NULL
, struct dns_connection
))) {
121 return ERROR_DNS_NO_MEMORY
;
124 memset(&hints
, 0, sizeof(struct addrinfo
));
125 hints
.ai_family
= AF_UNSPEC
;
126 hints
.ai_socktype
= SOCK_DGRAM
;
128 hints
.ai_protocol
= IPPROTO_UDP
;
130 ret
= getaddrinfo(nameserver
, service
, &hints
, &ai_result
);
132 DEBUG(1,("dns_ucp_open:getaddrinfo: %s\n", gai_strerror(ret
)));
134 return ERROR_DNS_INVALID_NAME_SERVER
;
137 for (rp
= ai_result
; rp
!= NULL
; rp
= rp
->ai_next
) {
138 conn
->s
= socket(rp
->ai_family
,
144 ret
= connect(conn
->s
, rp
->ai_addr
, rp
->ai_addrlen
);
146 /* Successful connect */
152 freeaddrinfo(ai_result
);
154 /* Failed to connect with any address */
157 return ERROR_DNS_CONNECTION_FAILED
;
160 talloc_set_destructor(conn
, destroy_dns_connection
);
162 /* Set up the RecvAddr structure with the IP address of
163 the receiver and the specified port number. */
165 RecvAddrLen
= sizeof(RecvAddr
);
166 if (getpeername(conn
->s
,
167 (struct sockaddr
*)&RecvAddr
,
168 &RecvAddrLen
) == -1) {
170 return ERROR_DNS_CONNECTION_FAILED
;
173 conn
->hType
= DNS_UDP
;
174 memcpy(&conn
->RecvAddr
, &RecvAddr
, sizeof(struct sockaddr_storage
));
177 return ERROR_DNS_SUCCESS
;
180 /********************************************************************
181 ********************************************************************/
183 DNS_ERROR
dns_open_connection( const char *nameserver
, int32_t dwType
,
185 struct dns_connection
**conn
)
189 return dns_tcp_open( nameserver
, mem_ctx
, conn
);
191 return dns_udp_open( nameserver
, mem_ctx
, conn
);
194 return ERROR_DNS_INVALID_PARAMETER
;
197 static DNS_ERROR
write_all(int fd
, uint8_t *data
, size_t len
)
201 while (total
< len
) {
206 ret
= write(fd
, data
+ total
, len
- total
);
207 } while ((ret
== -1) && (errno
== EINTR
));
213 return ERROR_DNS_SOCKET_ERROR
;
219 return ERROR_DNS_SUCCESS
;
222 static DNS_ERROR
dns_send_tcp(struct dns_connection
*conn
,
223 const struct dns_buffer
*buf
)
225 uint16_t len
= htons(buf
->offset
);
228 err
= write_all(conn
->s
, (uint8_t *)&len
, sizeof(len
));
229 if (!ERR_DNS_IS_OK(err
)) return err
;
231 return write_all(conn
->s
, buf
->data
, buf
->offset
);
234 static DNS_ERROR
dns_send_udp(struct dns_connection
*conn
,
235 const struct dns_buffer
*buf
)
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
));
245 if (ret
!= buf
->offset
) {
246 return ERROR_DNS_SOCKET_ERROR
;
249 return ERROR_DNS_SUCCESS
;
252 DNS_ERROR
dns_send(struct dns_connection
*conn
, const struct dns_buffer
*buf
)
254 if (conn
->hType
== DNS_TCP
) {
255 return dns_send_tcp(conn
, buf
);
258 if (conn
->hType
== DNS_UDP
) {
259 return dns_send_udp(conn
, buf
);
262 return ERROR_DNS_INVALID_PARAMETER
;
265 static DNS_ERROR
read_all(int fd
, uint8_t *data
, size_t len
)
269 while (total
< len
) {
276 pfd
.events
= POLLIN
|POLLHUP
;
278 fd_ready
= poll(&pfd
, 1, 10000);
279 if (fd_ready
== -1) {
280 if (errno
== EINTR
) {
283 return ERROR_DNS_SOCKET_ERROR
;
285 if ( fd_ready
== 0 ) {
287 return ERROR_DNS_SOCKET_ERROR
;
291 ret
= read(fd
, data
+ total
, len
- total
);
292 } while ((ret
== -1) && (errno
== EINTR
));
296 return ERROR_DNS_SOCKET_ERROR
;
302 return ERROR_DNS_SUCCESS
;
305 static DNS_ERROR
dns_receive_tcp(TALLOC_CTX
*mem_ctx
,
306 struct dns_connection
*conn
,
307 struct dns_buffer
**presult
)
309 struct dns_buffer
*buf
;
313 if (!(buf
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
314 return ERROR_DNS_NO_MEMORY
;
317 err
= read_all(conn
->s
, (uint8_t *)&len
, sizeof(len
));
318 if (!ERR_DNS_IS_OK(err
)) {
322 buf
->size
= ntohs(len
);
324 if (buf
->size
== 0) {
326 return ERROR_DNS_SUCCESS
;
329 if (!(buf
->data
= talloc_array(buf
, uint8_t, buf
->size
))) {
331 return ERROR_DNS_NO_MEMORY
;
334 err
= read_all(conn
->s
, buf
->data
, talloc_get_size(buf
->data
));
335 if (!ERR_DNS_IS_OK(err
)) {
341 return ERROR_DNS_SUCCESS
;
344 static DNS_ERROR
dns_receive_udp(TALLOC_CTX
*mem_ctx
,
345 struct dns_connection
*conn
,
346 struct dns_buffer
**presult
)
348 struct dns_buffer
*buf
;
351 if (!(buf
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
352 return ERROR_DNS_NO_MEMORY
;
356 * UDP based DNS can only be 512 bytes
359 if (!(buf
->data
= talloc_array(buf
, uint8_t, 512))) {
361 return ERROR_DNS_NO_MEMORY
;
365 received
= recv(conn
->s
, (void *)buf
->data
, 512, 0);
366 } while ((received
== -1) && (errno
== EINTR
));
368 if (received
== -1) {
370 return ERROR_DNS_SOCKET_ERROR
;
373 if (received
> 512) {
375 return ERROR_DNS_BAD_RESPONSE
;
378 buf
->size
= received
;
382 return ERROR_DNS_SUCCESS
;
385 DNS_ERROR
dns_receive(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
386 struct dns_buffer
**presult
)
388 if (conn
->hType
== DNS_TCP
) {
389 return dns_receive_tcp(mem_ctx
, conn
, presult
);
392 if (conn
->hType
== DNS_UDP
) {
393 return dns_receive_udp(mem_ctx
, conn
, presult
);
396 return ERROR_DNS_INVALID_PARAMETER
;
399 DNS_ERROR
dns_transaction(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
400 const struct dns_request
*req
,
401 struct dns_request
**resp
)
403 struct dns_buffer
*buf
= NULL
;
406 err
= dns_marshall_request(mem_ctx
, req
, &buf
);
407 if (!ERR_DNS_IS_OK(err
)) goto error
;
409 err
= dns_send(conn
, buf
);
410 if (!ERR_DNS_IS_OK(err
)) goto error
;
413 err
= dns_receive(mem_ctx
, conn
, &buf
);
414 if (!ERR_DNS_IS_OK(err
)) goto error
;
416 err
= dns_unmarshall_request(mem_ctx
, buf
, resp
);
423 DNS_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
)
428 struct dns_request
*resp
;
431 err
= dns_transaction(mem_ctx
, conn
, dns_update2request(up_req
),
434 if (!ERR_DNS_IS_OK(err
)) return err
;
436 *up_resp
= dns_request2update(resp
);
437 return ERROR_DNS_SUCCESS
;