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"
31 static int destroy_dns_connection(struct dns_connection
*conn
)
33 return close(conn
->s
);
36 /********************************************************************
37 ********************************************************************/
39 static DNS_ERROR
dns_tcp_open( const char *nameserver
,
41 struct dns_connection
**result
)
44 struct hostent
*pHost
;
45 struct sockaddr_in s_in
;
46 struct dns_connection
*conn
;
49 if (!(conn
= talloc(mem_ctx
, struct dns_connection
))) {
50 return ERROR_DNS_NO_MEMORY
;
53 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
54 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
56 return ERROR_DNS_INVALID_NAME_SERVER
;
58 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
61 conn
->s
= socket( PF_INET
, SOCK_STREAM
, 0 );
64 return ERROR_DNS_CONNECTION_FAILED
;
67 talloc_set_destructor(conn
, destroy_dns_connection
);
69 s_in
.sin_family
= AF_INET
;
70 s_in
.sin_addr
.s_addr
= ulAddress
;
71 s_in
.sin_port
= htons( DNS_TCP_PORT
);
73 res
= connect(conn
->s
, (struct sockaddr
*)&s_in
, sizeof( s_in
));
76 return ERROR_DNS_CONNECTION_FAILED
;
79 conn
->hType
= DNS_TCP
;
82 return ERROR_DNS_SUCCESS
;
85 /********************************************************************
86 ********************************************************************/
88 static DNS_ERROR
dns_udp_open( const char *nameserver
,
90 struct dns_connection
**result
)
92 unsigned long ulAddress
;
93 struct hostent
*pHost
;
94 struct sockaddr_in RecvAddr
;
95 struct dns_connection
*conn
;
97 if (!(conn
= talloc(NULL
, struct dns_connection
))) {
98 return ERROR_DNS_NO_MEMORY
;
101 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
102 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
104 return ERROR_DNS_INVALID_NAME_SERVER
;
106 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
109 /* Create a socket for sending data */
111 conn
->s
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
114 return ERROR_DNS_CONNECTION_FAILED
;
117 talloc_set_destructor(conn
, destroy_dns_connection
);
119 /* Set up the RecvAddr structure with the IP address of
120 the receiver (in this example case "123.456.789.1")
121 and the specified port number. */
123 ZERO_STRUCT(RecvAddr
);
124 RecvAddr
.sin_family
= AF_INET
;
125 RecvAddr
.sin_port
= htons( DNS_UDP_PORT
);
126 RecvAddr
.sin_addr
.s_addr
= ulAddress
;
128 conn
->hType
= DNS_UDP
;
129 memcpy( &conn
->RecvAddr
, &RecvAddr
, sizeof( struct sockaddr_in
) );
132 return ERROR_DNS_SUCCESS
;
135 /********************************************************************
136 ********************************************************************/
138 DNS_ERROR
dns_open_connection( const char *nameserver
, int32 dwType
,
140 struct dns_connection
**conn
)
144 return dns_tcp_open( nameserver
, mem_ctx
, conn
);
146 return dns_udp_open( nameserver
, mem_ctx
, conn
);
149 return ERROR_DNS_INVALID_PARAMETER
;
152 static DNS_ERROR
write_all(int fd
, uint8
*data
, size_t len
)
156 while (total
< len
) {
158 ssize_t ret
= write(fd
, data
+ total
, len
- total
);
164 return ERROR_DNS_SOCKET_ERROR
;
170 return ERROR_DNS_SUCCESS
;
173 static DNS_ERROR
dns_send_tcp(struct dns_connection
*conn
,
174 const struct dns_buffer
*buf
)
176 uint16 len
= htons(buf
->offset
);
179 err
= write_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
180 if (!ERR_DNS_IS_OK(err
)) return err
;
182 return write_all(conn
->s
, buf
->data
, buf
->offset
);
185 static DNS_ERROR
dns_send_udp(struct dns_connection
*conn
,
186 const struct dns_buffer
*buf
)
190 ret
= sendto(conn
->s
, buf
->data
, buf
->offset
, 0,
191 (struct sockaddr
*)&conn
->RecvAddr
,
192 sizeof(conn
->RecvAddr
));
194 if (ret
!= buf
->offset
) {
195 return ERROR_DNS_SOCKET_ERROR
;
198 return ERROR_DNS_SUCCESS
;
201 DNS_ERROR
dns_send(struct dns_connection
*conn
, const struct dns_buffer
*buf
)
203 if (conn
->hType
== DNS_TCP
) {
204 return dns_send_tcp(conn
, buf
);
207 if (conn
->hType
== DNS_UDP
) {
208 return dns_send_udp(conn
, buf
);
211 return ERROR_DNS_INVALID_PARAMETER
;
214 static DNS_ERROR
read_all(int fd
, uint8
*data
, size_t len
)
218 while (total
< len
) {
225 pfd
.events
= POLLIN
|POLLHUP
;
227 fd_ready
= poll(&pfd
, 1, 10000);
228 if ( fd_ready
== 0 ) {
230 return ERROR_DNS_SOCKET_ERROR
;
233 ret
= read(fd
, data
+ total
, len
- total
);
236 return ERROR_DNS_SOCKET_ERROR
;
242 return ERROR_DNS_SUCCESS
;
245 static DNS_ERROR
dns_receive_tcp(TALLOC_CTX
*mem_ctx
,
246 struct dns_connection
*conn
,
247 struct dns_buffer
**presult
)
249 struct dns_buffer
*buf
;
253 if (!(buf
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
254 return ERROR_DNS_NO_MEMORY
;
257 err
= read_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
258 if (!ERR_DNS_IS_OK(err
)) {
262 buf
->size
= ntohs(len
);
265 if (!(buf
->data
= talloc_array(buf
, uint8
, buf
->size
))) {
267 return ERROR_DNS_NO_MEMORY
;
273 err
= read_all(conn
->s
, buf
->data
, buf
->size
);
274 if (!ERR_DNS_IS_OK(err
)) {
280 return ERROR_DNS_SUCCESS
;
283 static DNS_ERROR
dns_receive_udp(TALLOC_CTX
*mem_ctx
,
284 struct dns_connection
*conn
,
285 struct dns_buffer
**presult
)
287 struct dns_buffer
*buf
;
290 if (!(buf
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
291 return ERROR_DNS_NO_MEMORY
;
295 * UDP based DNS can only be 512 bytes
298 if (!(buf
->data
= talloc_array(buf
, uint8
, 512))) {
300 return ERROR_DNS_NO_MEMORY
;
303 received
= recv(conn
->s
, (void *)buf
->data
, 512, 0);
305 if (received
== -1) {
307 return ERROR_DNS_SOCKET_ERROR
;
310 if (received
> 512) {
312 return ERROR_DNS_BAD_RESPONSE
;
315 buf
->size
= received
;
319 return ERROR_DNS_SUCCESS
;
322 DNS_ERROR
dns_receive(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
323 struct dns_buffer
**presult
)
325 if (conn
->hType
== DNS_TCP
) {
326 return dns_receive_tcp(mem_ctx
, conn
, presult
);
329 if (conn
->hType
== DNS_UDP
) {
330 return dns_receive_udp(mem_ctx
, conn
, presult
);
333 return ERROR_DNS_INVALID_PARAMETER
;
336 DNS_ERROR
dns_transaction(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
337 const struct dns_request
*req
,
338 struct dns_request
**resp
)
340 struct dns_buffer
*buf
= NULL
;
343 err
= dns_marshall_request(mem_ctx
, req
, &buf
);
344 if (!ERR_DNS_IS_OK(err
)) goto error
;
346 err
= dns_send(conn
, buf
);
347 if (!ERR_DNS_IS_OK(err
)) goto error
;
350 err
= dns_receive(mem_ctx
, conn
, &buf
);
351 if (!ERR_DNS_IS_OK(err
)) goto error
;
353 err
= dns_unmarshall_request(mem_ctx
, buf
, resp
);
360 DNS_ERROR
dns_update_transaction(TALLOC_CTX
*mem_ctx
,
361 struct dns_connection
*conn
,
362 struct dns_update_request
*up_req
,
363 struct dns_update_request
**up_resp
)
365 struct dns_request
*resp
;
368 err
= dns_transaction(mem_ctx
, conn
, dns_update2request(up_req
),
371 if (!ERR_DNS_IS_OK(err
)) return err
;
373 *up_resp
= dns_request2update(resp
);
374 return ERROR_DNS_SUCCESS
;